{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Stellargraph example: Personalised Propagation of Neural Predictions (PPNP) and Approximate PPNP (APPNP) on the CORA citation dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Import NetworkX and stellargraph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import networkx as nx\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import os\n",
    "from tensorflow import keras\n",
    "from tensorflow.keras import backend as K\n",
    "from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n",
    "\n",
    "import stellargraph as sg\n",
    "from stellargraph.mapper import FullBatchNodeGenerator\n",
    "from stellargraph.layer.ppnp import PPNP\n",
    "from stellargraph.layer.appnp import APPNP\n",
    "\n",
    "from tensorflow.keras import layers, optimizers, losses, metrics, Model\n",
    "from sklearn import preprocessing, feature_extraction, model_selection\n",
    "from stellargraph import datasets\n",
    "from IPython.display import display, HTML"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Loading the CORA network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "The Cora dataset consists of 2708 scientific publications classified into one of seven classes. The citation network consists of 5429 links. Each publication in the dataset is described by a 0/1-valued word vector indicating the absence/presence of the corresponding word from the dictionary. The dictionary consists of 1433 unique words."
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "dataset = datasets.Cora()\n",
    "display(HTML(dataset.description))\n",
    "dataset.download()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load the graph from edgelist (in the order `cited-paper` <- `citing-paper`)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "edgelist = pd.read_csv(\n",
    "    os.path.join(dataset.data_directory, \"cora.cites\"),\n",
    "    sep=\"\\t\",\n",
    "    header=None,\n",
    "    names=[\"target\", \"source\"],\n",
    ")\n",
    "edgelist[\"label\"] = \"cites\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "Gnx = nx.from_pandas_edgelist(edgelist, edge_attr=\"label\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "nx.set_node_attributes(Gnx, \"paper\", \"label\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Load the features and subject for the nodes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "feature_names = [\"w_{}\".format(ii) for ii in range(1433)]\n",
    "column_names = feature_names + [\"subject\"]\n",
    "node_data = pd.read_csv(\n",
    "    os.path.join(dataset.data_directory, \"cora.content\"),\n",
    "    sep=\"\\t\",\n",
    "    header=None,\n",
    "    names=column_names,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We aim to train a graph-ML model that will predict the \"subject\" attribute on the nodes. These subjects are one of 7 categories:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'Case_Based',\n",
       " 'Genetic_Algorithms',\n",
       " 'Neural_Networks',\n",
       " 'Probabilistic_Methods',\n",
       " 'Reinforcement_Learning',\n",
       " 'Rule_Learning',\n",
       " 'Theory'}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "set(node_data[\"subject\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Splitting the data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For machine learning we want to take a subset of the nodes for training, and use the rest for validation and testing. We'll use scikit-learn again to do this.\n",
    "\n",
    "Here we're taking 140 node labels for training, 500 for validation, and the rest for testing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_data, test_data = model_selection.train_test_split(\n",
    "    node_data, train_size=140, test_size=None, stratify=node_data[\"subject\"]\n",
    ")\n",
    "val_data, test_data = model_selection.train_test_split(\n",
    "    test_data, train_size=500, test_size=None, stratify=test_data[\"subject\"]\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note using stratified sampling gives the following counts:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({'Theory': 18,\n",
       "         'Case_Based': 16,\n",
       "         'Probabilistic_Methods': 22,\n",
       "         'Neural_Networks': 42,\n",
       "         'Reinforcement_Learning': 11,\n",
       "         'Genetic_Algorithms': 22,\n",
       "         'Rule_Learning': 9})"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import Counter\n",
    "\n",
    "Counter(train_data[\"subject\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The training set has class imbalance that might need to be compensated, e.g., via using a weighted cross-entropy loss in model training, with class weights inversely proportional to class support. However, we will ignore the class imbalance in this example, for simplicity."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Converting to numeric arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For our categorical target, we will use one-hot vectors that will be fed into a soft-max Keras layer during training. To do this conversion ..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "target_encoding = feature_extraction.DictVectorizer(sparse=False)\n",
    "\n",
    "train_targets = target_encoding.fit_transform(train_data[[\"subject\"]].to_dict(\"records\"))\n",
    "val_targets = target_encoding.transform(val_data[[\"subject\"]].to_dict(\"records\"))\n",
    "test_targets = target_encoding.transform(test_data[[\"subject\"]].to_dict(\"records\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We now do the same for the node attributes we want to use to predict the subject. These are the feature vectors that the Keras model will use as input. The CORA dataset contains attributes 'w_x' that correspond to words found in that publication. If a word occurs more than once in a publication the relevant attribute will be set to one, otherwise it will be zero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_features = node_data[feature_names]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating the PPNP model in Keras"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now create a StellarGraph object from the NetworkX graph and the node features and targets. It is StellarGraph objects that we use in this library to perform machine learning tasks on."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "G = sg.StellarGraph(Gnx, node_features=node_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NetworkXStellarGraph: Undirected multigraph\n",
      " Nodes: 2708, Edges: 5278\n",
      "\n",
      " Node types:\n",
      "  paper: [2708]\n",
      "    Edge types: paper-cites->paper\n",
      "\n",
      " Edge types:\n",
      "    paper-cites->paper: [5278]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(G.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To feed data from the graph to the Keras model we need a generator. Since PPNP is a full-batch model, we use the `FullBatchNodeGenerator` class to feed node features and the normalized graph Laplacian matrix to the model.\n",
    "\n",
    "Specifying the `method='ppnp'` argument to the `FullBatchNodeGenerator` will pre-process the adjacency matrix and supply the personalized page rank matrix necessary for PPNP.  The personalized page rank matrix is a dense matrix and so `sparse=False` must be passed to `FullBatchNodeGenerator`. `teleport_probability=0.1` specifies the probability of returning to the starting node in the propogation step as desribed in the paper (alpha in the paper). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "generator = FullBatchNodeGenerator(\n",
    "    G, method=\"ppnp\", sparse=False, teleport_probability=0.1\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For training we map only the training nodes returned from our splitter and the target values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_gen = generator.flow(train_data.index, train_targets)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can specify our machine learning model, we need a few more parameters for this:\n",
    "\n",
    " * the `layer_sizes` is a list of hidden feature sizes of each full fully connected layer in the model. In this example we use three fully connected layers with 64,64, and 7 hidden node features at each layer. \n",
    " * `activations` is a list of activations applied to each layer's output\n",
    " * `dropout=0.5` specifies a 50% dropout at each layer. \n",
    " * `kernel_regularizer=keras.regularizers.l2(0.001)` specifies a penality that prevents the model weights from become too large and helps limit overfitting\n",
    " \n",
    " #### Note that the size of the final fully connected layer must be equal to the number of classes you are trying to predict.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We create a PPNP model as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "ppnp = PPNP(\n",
    "    layer_sizes=[64, 64, train_targets.shape[-1]],\n",
    "    activations=[\"relu\", \"relu\", \"relu\"],\n",
    "    generator=generator,\n",
    "    dropout=0.5,\n",
    "    kernel_regularizer=keras.regularizers.l2(0.001),\n",
    ")\n",
    "\n",
    "x_inp, x_out = ppnp.build()\n",
    "predictions = keras.layers.Softmax()(x_out)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Training the model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's create the actual Keras model with the input tensors `x_inp` and output tensors being the predictions `predictions` from the final dense layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "ppnp_model = Model(inputs=x_inp, outputs=predictions)\n",
    "ppnp_model.compile(\n",
    "    optimizer=optimizers.Adam(lr=0.01),\n",
    "    loss=losses.categorical_crossentropy,\n",
    "    metrics=[\"acc\"],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Train the model, keeping track of its loss and accuracy on the training set, and its generalisation performance on the validation set (we need to create another generator over the validation data for this)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "val_gen = generator.flow(val_data.index, val_targets)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create callbacks for early stopping (if validation accuracy stops improving) and best model checkpoint saving:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "if not os.path.isdir(\"logs\"):\n",
    "    os.makedirs(\"logs\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "es_callback = EarlyStopping(\n",
    "    monitor=\"val_acc\", patience=50\n",
    ")  # patience is the number of epochs to wait before early stopping in case of no further improvement\n",
    "\n",
    "mc_callback = ModelCheckpoint(\n",
    "    \"logs/best_ppnp_model.h5\",\n",
    "    monitor=\"val_acc\",\n",
    "    save_best_only=True,\n",
    "    save_weights_only=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Train the model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/80\n",
      "1/1 - 0s - loss: 2.1346 - acc: 0.1571 - val_loss: 2.0704 - val_acc: 0.3160\n",
      "Epoch 2/80\n",
      "1/1 - 0s - loss: 2.0632 - acc: 0.3071 - val_loss: 2.0040 - val_acc: 0.3020\n",
      "Epoch 3/80\n",
      "1/1 - 0s - loss: 1.9805 - acc: 0.3357 - val_loss: 1.9447 - val_acc: 0.3020\n",
      "Epoch 4/80\n",
      "1/1 - 0s - loss: 1.9235 - acc: 0.3143 - val_loss: 1.8934 - val_acc: 0.3020\n",
      "Epoch 5/80\n",
      "1/1 - 0s - loss: 1.9011 - acc: 0.3071 - val_loss: 1.8374 - val_acc: 0.3120\n",
      "Epoch 6/80\n",
      "1/1 - 0s - loss: 1.9073 - acc: 0.3143 - val_loss: 1.7759 - val_acc: 0.4120\n",
      "Epoch 7/80\n",
      "1/1 - 0s - loss: 1.7542 - acc: 0.3786 - val_loss: 1.7268 - val_acc: 0.5380\n",
      "Epoch 8/80\n",
      "1/1 - 0s - loss: 1.7429 - acc: 0.3929 - val_loss: 1.6706 - val_acc: 0.5720\n",
      "Epoch 9/80\n",
      "1/1 - 0s - loss: 1.6998 - acc: 0.4357 - val_loss: 1.5957 - val_acc: 0.5740\n",
      "Epoch 10/80\n",
      "1/1 - 0s - loss: 1.6272 - acc: 0.4929 - val_loss: 1.5109 - val_acc: 0.5780\n",
      "Epoch 11/80\n",
      "1/1 - 0s - loss: 1.6323 - acc: 0.4286 - val_loss: 1.4356 - val_acc: 0.6120\n",
      "Epoch 12/80\n",
      "1/1 - 0s - loss: 1.4379 - acc: 0.5571 - val_loss: 1.3659 - val_acc: 0.6340\n",
      "Epoch 13/80\n",
      "1/1 - 0s - loss: 1.3829 - acc: 0.5500 - val_loss: 1.3055 - val_acc: 0.6760\n",
      "Epoch 14/80\n",
      "1/1 - 0s - loss: 1.3810 - acc: 0.5714 - val_loss: 1.2619 - val_acc: 0.7160\n",
      "Epoch 15/80\n",
      "1/1 - 0s - loss: 1.2570 - acc: 0.6571 - val_loss: 1.2390 - val_acc: 0.7240\n",
      "Epoch 16/80\n",
      "1/1 - 0s - loss: 1.2559 - acc: 0.6857 - val_loss: 1.2289 - val_acc: 0.7100\n",
      "Epoch 17/80\n",
      "1/1 - 0s - loss: 1.3349 - acc: 0.6786 - val_loss: 1.2173 - val_acc: 0.7040\n",
      "Epoch 18/80\n",
      "1/1 - 0s - loss: 1.1525 - acc: 0.7143 - val_loss: 1.1797 - val_acc: 0.7080\n",
      "Epoch 19/80\n",
      "1/1 - 0s - loss: 1.2098 - acc: 0.6929 - val_loss: 1.1349 - val_acc: 0.7260\n",
      "Epoch 20/80\n",
      "1/1 - 0s - loss: 1.1279 - acc: 0.6929 - val_loss: 1.1064 - val_acc: 0.7400\n",
      "Epoch 21/80\n",
      "1/1 - 0s - loss: 1.2893 - acc: 0.6714 - val_loss: 1.0945 - val_acc: 0.7400\n",
      "Epoch 22/80\n",
      "1/1 - 0s - loss: 1.0159 - acc: 0.7714 - val_loss: 1.0897 - val_acc: 0.7400\n",
      "Epoch 23/80\n",
      "1/1 - 0s - loss: 1.0486 - acc: 0.7214 - val_loss: 1.0895 - val_acc: 0.7300\n",
      "Epoch 24/80\n",
      "1/1 - 0s - loss: 1.1122 - acc: 0.7143 - val_loss: 1.0998 - val_acc: 0.7240\n",
      "Epoch 25/80\n",
      "1/1 - 0s - loss: 1.0085 - acc: 0.7500 - val_loss: 1.1221 - val_acc: 0.7140\n",
      "Epoch 26/80\n",
      "1/1 - 0s - loss: 1.0107 - acc: 0.7571 - val_loss: 1.1324 - val_acc: 0.7040\n",
      "Epoch 27/80\n",
      "1/1 - 0s - loss: 1.0002 - acc: 0.7500 - val_loss: 1.1219 - val_acc: 0.7020\n",
      "Epoch 28/80\n",
      "1/1 - 0s - loss: 0.9715 - acc: 0.8000 - val_loss: 1.0998 - val_acc: 0.7120\n",
      "Epoch 29/80\n",
      "1/1 - 0s - loss: 0.9029 - acc: 0.8071 - val_loss: 1.0751 - val_acc: 0.7260\n",
      "Epoch 30/80\n",
      "1/1 - 0s - loss: 0.9733 - acc: 0.7786 - val_loss: 1.0594 - val_acc: 0.7360\n",
      "Epoch 31/80\n",
      "1/1 - 0s - loss: 0.8914 - acc: 0.7857 - val_loss: 1.0488 - val_acc: 0.7400\n",
      "Epoch 32/80\n",
      "1/1 - 0s - loss: 0.9227 - acc: 0.7786 - val_loss: 1.0415 - val_acc: 0.7440\n",
      "Epoch 33/80\n",
      "1/1 - 0s - loss: 0.9545 - acc: 0.7643 - val_loss: 1.0420 - val_acc: 0.7400\n",
      "Epoch 34/80\n",
      "1/1 - 0s - loss: 0.9982 - acc: 0.7000 - val_loss: 1.0569 - val_acc: 0.7400\n",
      "Epoch 35/80\n",
      "1/1 - 0s - loss: 0.8389 - acc: 0.8143 - val_loss: 1.0645 - val_acc: 0.7320\n",
      "Epoch 36/80\n",
      "1/1 - 0s - loss: 0.8611 - acc: 0.8500 - val_loss: 1.0705 - val_acc: 0.7280\n",
      "Epoch 37/80\n",
      "1/1 - 0s - loss: 0.8544 - acc: 0.8143 - val_loss: 1.0760 - val_acc: 0.7300\n",
      "Epoch 38/80\n",
      "1/1 - 0s - loss: 0.9002 - acc: 0.7643 - val_loss: 1.0882 - val_acc: 0.7280\n",
      "Epoch 39/80\n",
      "1/1 - 0s - loss: 0.7870 - acc: 0.8000 - val_loss: 1.0923 - val_acc: 0.7340\n",
      "Epoch 40/80\n",
      "1/1 - 0s - loss: 0.7762 - acc: 0.8286 - val_loss: 1.0856 - val_acc: 0.7380\n",
      "Epoch 41/80\n",
      "1/1 - 0s - loss: 0.8874 - acc: 0.7786 - val_loss: 1.0783 - val_acc: 0.7440\n",
      "Epoch 42/80\n",
      "1/1 - 0s - loss: 0.7697 - acc: 0.8286 - val_loss: 1.0581 - val_acc: 0.7540\n",
      "Epoch 43/80\n",
      "1/1 - 0s - loss: 0.7499 - acc: 0.8714 - val_loss: 1.0416 - val_acc: 0.7660\n",
      "Epoch 44/80\n",
      "1/1 - 0s - loss: 0.8108 - acc: 0.8214 - val_loss: 1.0224 - val_acc: 0.7880\n",
      "Epoch 45/80\n",
      "1/1 - 0s - loss: 0.7854 - acc: 0.8357 - val_loss: 1.0043 - val_acc: 0.7960\n",
      "Epoch 46/80\n",
      "1/1 - 0s - loss: 0.8501 - acc: 0.8643 - val_loss: 1.0022 - val_acc: 0.7900\n",
      "Epoch 47/80\n",
      "1/1 - 0s - loss: 0.8226 - acc: 0.8214 - val_loss: 0.9881 - val_acc: 0.7960\n",
      "Epoch 48/80\n",
      "1/1 - 0s - loss: 0.9253 - acc: 0.7929 - val_loss: 0.9901 - val_acc: 0.7840\n",
      "Epoch 49/80\n",
      "1/1 - 0s - loss: 0.7118 - acc: 0.8500 - val_loss: 0.9960 - val_acc: 0.7840\n",
      "Epoch 50/80\n",
      "1/1 - 0s - loss: 0.8072 - acc: 0.8214 - val_loss: 0.9967 - val_acc: 0.7860\n",
      "Epoch 51/80\n",
      "1/1 - 0s - loss: 0.7622 - acc: 0.8429 - val_loss: 0.9961 - val_acc: 0.7880\n",
      "Epoch 52/80\n",
      "1/1 - 0s - loss: 0.8652 - acc: 0.8143 - val_loss: 1.0087 - val_acc: 0.7820\n",
      "Epoch 53/80\n",
      "1/1 - 0s - loss: 0.8116 - acc: 0.8000 - val_loss: 1.0200 - val_acc: 0.7600\n",
      "Epoch 54/80\n",
      "1/1 - 0s - loss: 0.7921 - acc: 0.8500 - val_loss: 1.0261 - val_acc: 0.7660\n",
      "Epoch 55/80\n",
      "1/1 - 0s - loss: 0.7714 - acc: 0.8643 - val_loss: 1.0320 - val_acc: 0.7720\n",
      "Epoch 56/80\n",
      "1/1 - 0s - loss: 0.9099 - acc: 0.8429 - val_loss: 1.0125 - val_acc: 0.7880\n",
      "Epoch 57/80\n",
      "1/1 - 0s - loss: 0.7381 - acc: 0.8714 - val_loss: 0.9929 - val_acc: 0.8080\n",
      "Epoch 58/80\n",
      "1/1 - 0s - loss: 0.6488 - acc: 0.9286 - val_loss: 0.9660 - val_acc: 0.8240\n",
      "Epoch 59/80\n",
      "1/1 - 0s - loss: 0.6264 - acc: 0.9357 - val_loss: 0.9534 - val_acc: 0.8280\n",
      "Epoch 60/80\n",
      "1/1 - 0s - loss: 0.7281 - acc: 0.8571 - val_loss: 0.9538 - val_acc: 0.8220\n",
      "Epoch 61/80\n",
      "1/1 - 0s - loss: 0.7256 - acc: 0.8429 - val_loss: 0.9561 - val_acc: 0.8160\n",
      "Epoch 62/80\n",
      "1/1 - 0s - loss: 0.7236 - acc: 0.8643 - val_loss: 0.9614 - val_acc: 0.8120\n",
      "Epoch 63/80\n",
      "1/1 - 0s - loss: 0.6953 - acc: 0.8786 - val_loss: 0.9708 - val_acc: 0.8060\n",
      "Epoch 64/80\n",
      "1/1 - 0s - loss: 0.7319 - acc: 0.8857 - val_loss: 0.9721 - val_acc: 0.8040\n",
      "Epoch 65/80\n",
      "1/1 - 0s - loss: 0.6326 - acc: 0.9071 - val_loss: 0.9853 - val_acc: 0.7980\n",
      "Epoch 66/80\n",
      "1/1 - 0s - loss: 0.7017 - acc: 0.8929 - val_loss: 0.9873 - val_acc: 0.8040\n",
      "Epoch 67/80\n",
      "1/1 - 0s - loss: 0.6538 - acc: 0.9000 - val_loss: 0.9890 - val_acc: 0.8040\n",
      "Epoch 68/80\n",
      "1/1 - 0s - loss: 0.6167 - acc: 0.9000 - val_loss: 0.9774 - val_acc: 0.8180\n",
      "Epoch 69/80\n",
      "1/1 - 0s - loss: 0.7546 - acc: 0.8571 - val_loss: 0.9734 - val_acc: 0.8160\n",
      "Epoch 70/80\n",
      "1/1 - 0s - loss: 0.6211 - acc: 0.9357 - val_loss: 0.9692 - val_acc: 0.8160\n",
      "Epoch 71/80\n",
      "1/1 - 0s - loss: 0.7038 - acc: 0.8571 - val_loss: 0.9665 - val_acc: 0.8180\n",
      "Epoch 72/80\n",
      "1/1 - 0s - loss: 0.6694 - acc: 0.8857 - val_loss: 0.9673 - val_acc: 0.8200\n",
      "Epoch 73/80\n",
      "1/1 - 0s - loss: 0.6722 - acc: 0.9000 - val_loss: 0.9601 - val_acc: 0.8320\n",
      "Epoch 74/80\n",
      "1/1 - 0s - loss: 0.6267 - acc: 0.9071 - val_loss: 0.9539 - val_acc: 0.8280\n",
      "Epoch 75/80\n",
      "1/1 - 0s - loss: 0.6256 - acc: 0.9143 - val_loss: 0.9522 - val_acc: 0.8220\n",
      "Epoch 76/80\n",
      "1/1 - 0s - loss: 0.6220 - acc: 0.9286 - val_loss: 0.9531 - val_acc: 0.8180\n",
      "Epoch 77/80\n",
      "1/1 - 0s - loss: 0.7084 - acc: 0.9429 - val_loss: 0.9643 - val_acc: 0.8100\n",
      "Epoch 78/80\n",
      "1/1 - 0s - loss: 0.7039 - acc: 0.8571 - val_loss: 0.9760 - val_acc: 0.8040\n",
      "Epoch 79/80\n",
      "1/1 - 0s - loss: 0.5649 - acc: 0.9429 - val_loss: 0.9856 - val_acc: 0.7960\n",
      "Epoch 80/80\n",
      "1/1 - 0s - loss: 0.6924 - acc: 0.9071 - val_loss: 0.9798 - val_acc: 0.8000\n"
     ]
    }
   ],
   "source": [
    "history = ppnp_model.fit_generator(\n",
    "    train_gen,\n",
    "    epochs=80,\n",
    "    validation_data=val_gen,\n",
    "    verbose=2,\n",
    "    shuffle=False,  # this should be False, since shuffling data means shuffling the whole graph\n",
    "    callbacks=[es_callback, mc_callback],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plot the training history:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "def remove_prefix(text, prefix):\n",
    "    return text[text.startswith(prefix) and len(prefix):]\n",
    "\n",
    "def plot_history(history):\n",
    "    metrics = sorted(set([remove_prefix(m, \"val_\") for m in list(history.history.keys())]))\n",
    "    for m in metrics:\n",
    "        # summarize history for metric m\n",
    "        plt.plot(history.history[m])\n",
    "        plt.plot(history.history['val_' + m])\n",
    "        plt.title(m)\n",
    "        plt.ylabel(m)\n",
    "        plt.xlabel('epoch')\n",
    "        plt.legend(['train', 'validation'], loc='best')\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_history(history)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Reload the saved weights of the best model found during the training (according to validation accuracy)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "ppnp_model.load_weights(\"logs/best_ppnp_model.h5\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Evaluate the best model on the test set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_gen = generator.flow(test_data.index, test_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Test Set Metrics:\n",
      "\tloss: 0.9248\n",
      "\tacc: 0.8356\n"
     ]
    }
   ],
   "source": [
    "test_metrics = ppnp_model.evaluate_generator(test_gen)\n",
    "print(\"\\nTest Set Metrics:\")\n",
    "for name, val in zip(ppnp_model.metrics_names, test_metrics):\n",
    "    print(\"\\t{}: {:0.4f}\".format(name, val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using the Approximate PPNP Model\n",
    "\n",
    "Lets repeat the training and testing steps with the APPNP model using the same dataset. The downside of the PPNP is that you have to invert the adjacency matrix - which is time inneficient for large graphs - and store that invert matrix - which is space innefficient. The approximate model avoids this issue by using a clever mathematical trick. \n",
    "\n",
    "The APPNP model uses the normalized graph Laplacian. To get the normalized graph Laplacian we create a new `FullBatchNodeGenerator` and set `method=\"gcn\"`. We have the option of choosing `sparse=True` or `sparse=False` but will use `sparse=True` for memory efficiency."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using GCN (local pooling) filters...\n",
      "Epoch 1/120\n",
      "1/1 - 0s - loss: 2.1595 - acc: 0.1357 - val_loss: 2.0784 - val_acc: 0.3020\n",
      "Epoch 2/120\n",
      "1/1 - 0s - loss: 2.1001 - acc: 0.2429 - val_loss: 2.0318 - val_acc: 0.3020\n",
      "Epoch 3/120\n",
      "1/1 - 0s - loss: 2.0691 - acc: 0.2500 - val_loss: 2.0005 - val_acc: 0.3020\n",
      "Epoch 4/120\n",
      "1/1 - 0s - loss: 1.9739 - acc: 0.3000 - val_loss: 1.9603 - val_acc: 0.3020\n",
      "Epoch 5/120\n",
      "1/1 - 0s - loss: 1.9215 - acc: 0.3071 - val_loss: 1.9105 - val_acc: 0.3020\n",
      "Epoch 6/120\n",
      "1/1 - 0s - loss: 1.9614 - acc: 0.2643 - val_loss: 1.8699 - val_acc: 0.3020\n",
      "Epoch 7/120\n",
      "1/1 - 0s - loss: 1.8598 - acc: 0.3357 - val_loss: 1.8196 - val_acc: 0.3260\n",
      "Epoch 8/120\n",
      "1/1 - 0s - loss: 1.8569 - acc: 0.3929 - val_loss: 1.7715 - val_acc: 0.4480\n",
      "Epoch 9/120\n",
      "1/1 - 0s - loss: 1.8282 - acc: 0.3429 - val_loss: 1.7245 - val_acc: 0.5280\n",
      "Epoch 10/120\n",
      "1/1 - 0s - loss: 1.7235 - acc: 0.4214 - val_loss: 1.6643 - val_acc: 0.5740\n",
      "Epoch 11/120\n",
      "1/1 - 0s - loss: 1.9225 - acc: 0.4071 - val_loss: 1.6321 - val_acc: 0.6140\n",
      "Epoch 12/120\n",
      "1/1 - 0s - loss: 1.7584 - acc: 0.4143 - val_loss: 1.5764 - val_acc: 0.6240\n",
      "Epoch 13/120\n",
      "1/1 - 0s - loss: 1.7068 - acc: 0.5214 - val_loss: 1.5167 - val_acc: 0.6360\n",
      "Epoch 14/120\n",
      "1/1 - 0s - loss: 1.5731 - acc: 0.5357 - val_loss: 1.4557 - val_acc: 0.6920\n",
      "Epoch 15/120\n",
      "1/1 - 0s - loss: 1.4960 - acc: 0.5500 - val_loss: 1.3937 - val_acc: 0.6960\n",
      "Epoch 16/120\n",
      "1/1 - 0s - loss: 1.4806 - acc: 0.5429 - val_loss: 1.3372 - val_acc: 0.6660\n",
      "Epoch 17/120\n",
      "1/1 - 0s - loss: 1.4523 - acc: 0.6071 - val_loss: 1.2886 - val_acc: 0.6660\n",
      "Epoch 18/120\n",
      "1/1 - 0s - loss: 1.4261 - acc: 0.6214 - val_loss: 1.2451 - val_acc: 0.6740\n",
      "Epoch 19/120\n",
      "1/1 - 0s - loss: 1.5576 - acc: 0.6000 - val_loss: 1.2082 - val_acc: 0.7080\n",
      "Epoch 20/120\n",
      "1/1 - 0s - loss: 1.3359 - acc: 0.6643 - val_loss: 1.1807 - val_acc: 0.7200\n",
      "Epoch 21/120\n",
      "1/1 - 0s - loss: 1.3872 - acc: 0.6286 - val_loss: 1.1706 - val_acc: 0.7380\n",
      "Epoch 22/120\n",
      "1/1 - 0s - loss: 1.3306 - acc: 0.6214 - val_loss: 1.1733 - val_acc: 0.7360\n",
      "Epoch 23/120\n",
      "1/1 - 0s - loss: 1.2333 - acc: 0.6857 - val_loss: 1.1898 - val_acc: 0.7200\n",
      "Epoch 24/120\n",
      "1/1 - 0s - loss: 1.3533 - acc: 0.6571 - val_loss: 1.2024 - val_acc: 0.7080\n",
      "Epoch 25/120\n",
      "1/1 - 0s - loss: 1.2550 - acc: 0.6643 - val_loss: 1.2085 - val_acc: 0.6980\n",
      "Epoch 26/120\n",
      "1/1 - 0s - loss: 1.1661 - acc: 0.7214 - val_loss: 1.2012 - val_acc: 0.7040\n",
      "Epoch 27/120\n",
      "1/1 - 0s - loss: 1.1447 - acc: 0.7286 - val_loss: 1.1859 - val_acc: 0.7100\n",
      "Epoch 28/120\n",
      "1/1 - 0s - loss: 1.2424 - acc: 0.7000 - val_loss: 1.1706 - val_acc: 0.7160\n",
      "Epoch 29/120\n",
      "1/1 - 0s - loss: 1.1540 - acc: 0.7214 - val_loss: 1.1574 - val_acc: 0.7200\n",
      "Epoch 30/120\n",
      "1/1 - 0s - loss: 1.1016 - acc: 0.7571 - val_loss: 1.1518 - val_acc: 0.7180\n",
      "Epoch 31/120\n",
      "1/1 - 0s - loss: 1.0691 - acc: 0.7571 - val_loss: 1.1489 - val_acc: 0.7140\n",
      "Epoch 32/120\n",
      "1/1 - 0s - loss: 1.2666 - acc: 0.7071 - val_loss: 1.1513 - val_acc: 0.7220\n",
      "Epoch 33/120\n",
      "1/1 - 0s - loss: 1.1708 - acc: 0.7357 - val_loss: 1.1536 - val_acc: 0.7320\n",
      "Epoch 34/120\n",
      "1/1 - 0s - loss: 1.0945 - acc: 0.7571 - val_loss: 1.1506 - val_acc: 0.7700\n",
      "Epoch 35/120\n",
      "1/1 - 0s - loss: 1.0722 - acc: 0.7571 - val_loss: 1.1555 - val_acc: 0.7640\n",
      "Epoch 36/120\n",
      "1/1 - 0s - loss: 1.0638 - acc: 0.7571 - val_loss: 1.1564 - val_acc: 0.7700\n",
      "Epoch 37/120\n",
      "1/1 - 0s - loss: 1.2757 - acc: 0.7857 - val_loss: 1.1509 - val_acc: 0.7720\n",
      "Epoch 38/120\n",
      "1/1 - 0s - loss: 1.1480 - acc: 0.7929 - val_loss: 1.1453 - val_acc: 0.7760\n",
      "Epoch 39/120\n",
      "1/1 - 0s - loss: 1.0517 - acc: 0.8143 - val_loss: 1.1387 - val_acc: 0.7700\n",
      "Epoch 40/120\n",
      "1/1 - 0s - loss: 1.0218 - acc: 0.7714 - val_loss: 1.1355 - val_acc: 0.7640\n",
      "Epoch 41/120\n",
      "1/1 - 0s - loss: 1.0021 - acc: 0.8000 - val_loss: 1.1383 - val_acc: 0.7560\n",
      "Epoch 42/120\n",
      "1/1 - 0s - loss: 1.0856 - acc: 0.7929 - val_loss: 1.1446 - val_acc: 0.7460\n",
      "Epoch 43/120\n",
      "1/1 - 0s - loss: 1.0420 - acc: 0.8000 - val_loss: 1.1419 - val_acc: 0.7400\n",
      "Epoch 44/120\n",
      "1/1 - 0s - loss: 1.0254 - acc: 0.7500 - val_loss: 1.1328 - val_acc: 0.7360\n",
      "Epoch 45/120\n",
      "1/1 - 0s - loss: 0.9758 - acc: 0.8214 - val_loss: 1.1230 - val_acc: 0.7420\n",
      "Epoch 46/120\n",
      "1/1 - 0s - loss: 0.9331 - acc: 0.8357 - val_loss: 1.1128 - val_acc: 0.7580\n",
      "Epoch 47/120\n",
      "1/1 - 0s - loss: 1.1889 - acc: 0.7929 - val_loss: 1.1091 - val_acc: 0.7640\n",
      "Epoch 48/120\n",
      "1/1 - 0s - loss: 1.0772 - acc: 0.8214 - val_loss: 1.1072 - val_acc: 0.7700\n",
      "Epoch 49/120\n",
      "1/1 - 0s - loss: 0.9875 - acc: 0.8214 - val_loss: 1.0996 - val_acc: 0.7860\n",
      "Epoch 50/120\n",
      "1/1 - 0s - loss: 0.8608 - acc: 0.8286 - val_loss: 1.0926 - val_acc: 0.7820\n",
      "Epoch 51/120\n",
      "1/1 - 0s - loss: 0.8624 - acc: 0.8500 - val_loss: 1.0868 - val_acc: 0.7840\n",
      "Epoch 52/120\n",
      "1/1 - 0s - loss: 0.9915 - acc: 0.8000 - val_loss: 1.0885 - val_acc: 0.7900\n",
      "Epoch 53/120\n",
      "1/1 - 0s - loss: 1.0176 - acc: 0.8643 - val_loss: 1.1024 - val_acc: 0.7840\n",
      "Epoch 54/120\n",
      "1/1 - 0s - loss: 1.1147 - acc: 0.8214 - val_loss: 1.1179 - val_acc: 0.7780\n",
      "Epoch 55/120\n",
      "1/1 - 0s - loss: 1.1655 - acc: 0.8143 - val_loss: 1.1307 - val_acc: 0.7600\n",
      "Epoch 56/120\n",
      "1/1 - 0s - loss: 0.9976 - acc: 0.8143 - val_loss: 1.1405 - val_acc: 0.7480\n",
      "Epoch 57/120\n",
      "1/1 - 0s - loss: 0.8833 - acc: 0.8500 - val_loss: 1.1532 - val_acc: 0.7360\n",
      "Epoch 58/120\n",
      "1/1 - 0s - loss: 0.8811 - acc: 0.8143 - val_loss: 1.1717 - val_acc: 0.7300\n",
      "Epoch 59/120\n",
      "1/1 - 0s - loss: 1.0116 - acc: 0.8143 - val_loss: 1.1650 - val_acc: 0.7300\n",
      "Epoch 60/120\n",
      "1/1 - 0s - loss: 0.8644 - acc: 0.8714 - val_loss: 1.1506 - val_acc: 0.7380\n",
      "Epoch 61/120\n",
      "1/1 - 0s - loss: 0.8631 - acc: 0.8643 - val_loss: 1.1469 - val_acc: 0.7340\n",
      "Epoch 62/120\n",
      "1/1 - 0s - loss: 0.9321 - acc: 0.8071 - val_loss: 1.1470 - val_acc: 0.7300\n",
      "Epoch 63/120\n",
      "1/1 - 0s - loss: 0.8553 - acc: 0.8500 - val_loss: 1.1433 - val_acc: 0.7360\n",
      "Epoch 64/120\n",
      "1/1 - 0s - loss: 1.0337 - acc: 0.8000 - val_loss: 1.1365 - val_acc: 0.7520\n",
      "Epoch 65/120\n",
      "1/1 - 0s - loss: 0.9428 - acc: 0.8429 - val_loss: 1.1306 - val_acc: 0.7580\n",
      "Epoch 66/120\n",
      "1/1 - 0s - loss: 0.8508 - acc: 0.8571 - val_loss: 1.1263 - val_acc: 0.7640\n",
      "Epoch 67/120\n",
      "1/1 - 0s - loss: 0.9712 - acc: 0.8500 - val_loss: 1.1272 - val_acc: 0.7640\n",
      "Epoch 68/120\n",
      "1/1 - 0s - loss: 0.8699 - acc: 0.8643 - val_loss: 1.1308 - val_acc: 0.7620\n",
      "Epoch 69/120\n",
      "1/1 - 0s - loss: 0.8779 - acc: 0.8714 - val_loss: 1.1442 - val_acc: 0.7560\n",
      "Epoch 70/120\n",
      "1/1 - 0s - loss: 1.0340 - acc: 0.8500 - val_loss: 1.1497 - val_acc: 0.7520\n",
      "Epoch 71/120\n",
      "1/1 - 0s - loss: 0.9042 - acc: 0.8357 - val_loss: 1.1535 - val_acc: 0.7380\n",
      "Epoch 72/120\n",
      "1/1 - 0s - loss: 0.9044 - acc: 0.8429 - val_loss: 1.1480 - val_acc: 0.7460\n",
      "Epoch 73/120\n",
      "1/1 - 0s - loss: 0.8384 - acc: 0.8500 - val_loss: 1.1474 - val_acc: 0.7400\n",
      "Epoch 74/120\n",
      "1/1 - 0s - loss: 0.9337 - acc: 0.8500 - val_loss: 1.1500 - val_acc: 0.7320\n",
      "Epoch 75/120\n",
      "1/1 - 0s - loss: 0.8164 - acc: 0.8929 - val_loss: 1.1532 - val_acc: 0.7320\n",
      "Epoch 76/120\n",
      "1/1 - 0s - loss: 1.0853 - acc: 0.8286 - val_loss: 1.1576 - val_acc: 0.7280\n",
      "Epoch 77/120\n",
      "1/1 - 0s - loss: 0.8514 - acc: 0.8714 - val_loss: 1.1606 - val_acc: 0.7180\n",
      "Epoch 78/120\n",
      "1/1 - 0s - loss: 0.8196 - acc: 0.8786 - val_loss: 1.1680 - val_acc: 0.7320\n",
      "Epoch 79/120\n",
      "1/1 - 0s - loss: 0.8982 - acc: 0.8571 - val_loss: 1.1817 - val_acc: 0.7280\n",
      "Epoch 80/120\n",
      "1/1 - 0s - loss: 0.8881 - acc: 0.8429 - val_loss: 1.1843 - val_acc: 0.7300\n",
      "Epoch 81/120\n",
      "1/1 - 0s - loss: 0.9616 - acc: 0.8357 - val_loss: 1.1642 - val_acc: 0.7380\n",
      "Epoch 82/120\n",
      "1/1 - 0s - loss: 0.8177 - acc: 0.8857 - val_loss: 1.1455 - val_acc: 0.7500\n",
      "Epoch 83/120\n",
      "1/1 - 0s - loss: 0.8592 - acc: 0.8714 - val_loss: 1.1342 - val_acc: 0.7480\n",
      "Epoch 84/120\n",
      "1/1 - 0s - loss: 0.9737 - acc: 0.8071 - val_loss: 1.1420 - val_acc: 0.7460\n",
      "Epoch 85/120\n",
      "1/1 - 0s - loss: 1.0191 - acc: 0.8071 - val_loss: 1.1493 - val_acc: 0.7420\n",
      "Epoch 86/120\n",
      "1/1 - 0s - loss: 0.9855 - acc: 0.8571 - val_loss: 1.1513 - val_acc: 0.7480\n",
      "Epoch 87/120\n",
      "1/1 - 0s - loss: 0.7953 - acc: 0.8714 - val_loss: 1.1627 - val_acc: 0.7400\n",
      "Epoch 88/120\n",
      "1/1 - 0s - loss: 1.0151 - acc: 0.8000 - val_loss: 1.1753 - val_acc: 0.7320\n",
      "Epoch 89/120\n",
      "1/1 - 0s - loss: 0.9478 - acc: 0.8786 - val_loss: 1.1862 - val_acc: 0.7300\n",
      "Epoch 90/120\n",
      "1/1 - 0s - loss: 0.9760 - acc: 0.8357 - val_loss: 1.2030 - val_acc: 0.7280\n",
      "Epoch 91/120\n",
      "1/1 - 0s - loss: 0.8642 - acc: 0.8714 - val_loss: 1.2154 - val_acc: 0.7320\n",
      "Epoch 92/120\n",
      "1/1 - 0s - loss: 0.9664 - acc: 0.8500 - val_loss: 1.2060 - val_acc: 0.7420\n",
      "Epoch 93/120\n",
      "1/1 - 0s - loss: 0.8439 - acc: 0.8714 - val_loss: 1.1855 - val_acc: 0.7480\n",
      "Epoch 94/120\n",
      "1/1 - 0s - loss: 0.8706 - acc: 0.8857 - val_loss: 1.1584 - val_acc: 0.7540\n",
      "Epoch 95/120\n",
      "1/1 - 0s - loss: 0.8488 - acc: 0.8714 - val_loss: 1.1458 - val_acc: 0.7640\n",
      "Epoch 96/120\n",
      "1/1 - 0s - loss: 0.9021 - acc: 0.8571 - val_loss: 1.1379 - val_acc: 0.7640\n",
      "Epoch 97/120\n",
      "1/1 - 0s - loss: 0.8226 - acc: 0.8857 - val_loss: 1.1345 - val_acc: 0.7620\n",
      "Epoch 98/120\n",
      "1/1 - 0s - loss: 0.8784 - acc: 0.8429 - val_loss: 1.1364 - val_acc: 0.7620\n",
      "Epoch 99/120\n",
      "1/1 - 0s - loss: 0.8704 - acc: 0.8714 - val_loss: 1.1485 - val_acc: 0.7520\n",
      "Epoch 100/120\n",
      "1/1 - 0s - loss: 1.0254 - acc: 0.7857 - val_loss: 1.1493 - val_acc: 0.7520\n",
      "Epoch 101/120\n",
      "1/1 - 0s - loss: 0.9215 - acc: 0.8857 - val_loss: 1.1534 - val_acc: 0.7520\n",
      "Epoch 102/120\n",
      "1/1 - 0s - loss: 0.7669 - acc: 0.9000 - val_loss: 1.1534 - val_acc: 0.7500\n"
     ]
    }
   ],
   "source": [
    "generator = FullBatchNodeGenerator(G, method=\"gcn\", sparse=True)\n",
    "\n",
    "train_gen = generator.flow(train_data.index, train_targets)\n",
    "val_gen = generator.flow(val_data.index, val_targets)\n",
    "test_gen = generator.flow(test_data.index, test_targets)\n",
    "\n",
    "appnp = APPNP(\n",
    "    layer_sizes=[64, 64, train_targets.shape[-1]],\n",
    "    activations=[\"relu\", \"relu\", \"relu\"],\n",
    "    bias=True,\n",
    "    generator=generator,\n",
    "    teleport_probability=0.1,\n",
    "    dropout=0.5,\n",
    "    kernel_regularizer=keras.regularizers.l2(0.001),\n",
    ")\n",
    "\n",
    "x_inp, x_out = appnp.build()\n",
    "predictions = keras.layers.Softmax()(x_out)\n",
    "\n",
    "appnp_model = keras.models.Model(inputs=x_inp, outputs=predictions)\n",
    "appnp_model.compile(\n",
    "    loss=\"categorical_crossentropy\",\n",
    "    metrics=[\"acc\"],\n",
    "    optimizer=keras.optimizers.Adam(lr=0.01),\n",
    ")\n",
    "\n",
    "es_callback = EarlyStopping(\n",
    "    monitor=\"val_acc\", patience=50\n",
    ")  # patience is the number of epochs to wait before early stopping in case of no further improvement\n",
    "\n",
    "mc_callback = ModelCheckpoint(\n",
    "    \"logs/best_appnp_model.h5\",\n",
    "    monitor=\"val_acc\",\n",
    "    save_best_only=True,\n",
    "    save_weights_only=True,\n",
    ")\n",
    "\n",
    "history = appnp_model.fit_generator(\n",
    "    train_gen,\n",
    "    epochs=120,\n",
    "    validation_data=val_gen,\n",
    "    verbose=2,\n",
    "    shuffle=False,  # this should be False, since shuffling data means shuffling the whole graph\n",
    "    callbacks=[es_callback, mc_callback],\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYIAAAEWCAYAAABrDZDcAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nOzdd3yV1f3A8c/Jzd6bBEISRiAhbMJQhiiI4EARFVFr1Z/Suq3aVjtcrdW2FrVWrbsuRMUBKogLBGRI2IEEQhbZe+/knt8fT3KzIesmAb7v14sXuc9z7nNPIHm+z1nfo7TWCCGEOHvZ9HcFhBBC9C8JBEIIcZaTQCCEEGc5CQRCCHGWk0AghBBnOQkEQghxlpNAIIQQZzkJBEIIcZaTQCCEEGc5CQRCdJJS6iGlVIJSqlQpdUQptaTZuduUUrHNzk1uOD5UKfWpUipXKZWvlPpP/30HQrTPtr8rIMRpJAGYDWQBVwPvKaVGArOAx4ArgGhgBFCrlDIBXwI/AL8A6oGovq+2ECenJNeQEN2jlNoPPArcAazXWj/f6vw5wDogUGtd1w9VFKJTpGtIiE5SSt2olNqvlCpSShUBYwFfYChGa6G1oUCKBAEx0EnXkBCdoJQKAV4D5gE7tNb1DS0CBaRidAe1lgoEK6VsJRiIgUxaBEJ0jguggVwApdTNGC0CgNeBB5VSU5RhZEPg+BnIBJ5WSrkopRyVUjP7o/JCnIwEAiE6QWt9BPgXsAPIBsYBPzWc+xh4ElgFlAKfA95a63rgMmAkcAJIA5b1eeWFOAUZLBZCiLOctAiEEOIsJ4FACCHOchIIhBDiLCeBQAghznKn3ToCX19fHRoa2t/VEEKI08qePXvytNZ+7Z077QJBaGgo0dHR/V0NIYQ4rSilUjo6J11DQghxlpNAIIQQZzkJBEIIcZY77cYI2lNbW0taWhpVVVX9XZUzgqOjI0FBQdjZ2fV3VYQQfeCMCARpaWm4ubkRGhqKUqq/q3Na01qTn59PWloaw4YN6+/qCCH6gFW7hpRSC5VSR5VSx5VSD7VzPkQp9b1S6qBSarNSKqg7n1NVVYWPj48EgV6glMLHx0daV0KcRawWCBq26XsRWASMAZYrpca0KvYM8I7WejzwBPBUDz6vu28Vrci/pRBnF2u2CKYBx7XWiVrrGmA1cHmrMmMw9nMF2NTOeSGEOOvVmzVPfnWEtMIKq1zfmoFgCMYOTY3SGo41dwC4suHrJYCbUsqn9YWUUiuUUtFKqejc3FyrVLYnioqKeOmll7r8vosvvpiioiIr1EgIcSb51zdHeW1rElvj86xy/f6ePvogcJ5Sah9wHpAO1LcupLV+VWsdpbWO8vNrd4V0v+ooENTVnXx3wvXr1+Pp6WmtagkxIBzPKeO5744he590z7oDGby0OYHl04K5dupQq3yGNWcNpWNs3t0oqOGYhdY6g4YWgVLKFViqtT7tHpEfeughEhISmDhxInZ2djg6OuLl5UVcXBzHjh3jiiuuIDU1laqqKu69915WrFgBNKXLKCsrY9GiRcyaNYvt27czZMgQ1q5di5OTUz9/Z0L03Bvbkvjg5xMsnRzEUG/n/q7OaSUmvZjfrTnA1FAvHl8cabXxO2sGgt1AmFJqGEYAuBa4rnkBpZQvUKC1NgMPA2/29EMf/+IwRzJKenqZFsYMdufRyyI7PP/0008TExPD/v372bx5M5dccgkxMTGW6Zdvvvkm3t7eVFZWMnXqVJYuXYqPT8sesPj4eD744ANee+01rrnmGj755BNuuOGGXv0+hOhrWmu2xhvdubGZJb0WCI5mlfL0hlieXjqeQe6OvXLNnkjJL+cvXx7hvvmjGDvEo90yxRW13P/Rfv5wSQQj/FxPec2q2np+9e4evJ3tefmGKdjbWq8Dx2pX1lrXAXcBG4FY4COt9WGl1BNKqcUNxeYCR5VSx4BBGPu+nvamTZvWYg7+v//9byZMmMCMGTNITU0lPj6+zXuGDRvGxIkTAZgyZQrJycl9VV0hrCYlv4K0wkoAYjNLe+26XxzIYNPRXFa8u4eq2ja9yX2qrLqO296J5rvYHG57J5rc0up2y30YfYLv43L4bG96u+dbS8orJ72okt8tDMfX1aE3q9yGVReUaa3XA+tbHXuk2ddrgDW9+Zkne3LvKy4uLpavN2/ezHfffceOHTtwdnZm7ty57c7Rd3Bo+o82mUxUVlb2SV2FsKbG1oCbgy1xWe231IsravnnN3HsSizggxUzOnXT251cgJezHQdSi/jjZzE8c/X4HnebJOWVc8v/dvP2zdMI9ulcy8Vs1vzmw/0k5JbzyKVj+MfGOG5/bw/v3zYdB1tTi3Krdp0AjH+TBy8afcprZxQZ94CQTtalJ/p7sPiM4ObmRmlp+087xcXFeHl54ezsTFxcHDt37uzj2okzSb1ZU1dv7pPPMpt1j5+2t8bnMdTbiZkjfYnLavk7orXm071pzFu5mVW7TpCQW8YL37dtLbdWU2dmf2oRSyYFcd/8MD7Zm8Yb25K6VK/2vq+fk/JJyitn4+GsNucqa9r/d3j2u2N8eySbP18SwS2zhvHPqyYQnVLIo2sPtxgc356QT3J+BaMHuXEwvZjC8po29Wk9mN4YCIZ4Wn+sUAJBL/Dx8WHmzJmMHTuW3/72ty3OLVy4kLq6OiIiInjooYeYMWNGP9VSnAke/+IwU5/8jg93n8Bstt4snP2pRVz2n23M/scmiitqu3WNunozOxLymTXSj4hAd5Lzy6moaZpJ93F0Gvd/dIAgL2fW3TWLa6cF8/6uEyTllZ/0uocziqmuMzM11It7LghjYWQAf1sfa7lxnsqqXScY++hGEnPLWhxPbPjcLfEtp6gfSC1i3GMb+fFYy+M7E/N54YfjLIsayi/PDQXgsgmDufP8Eazenco7O5rS/7+3MwVvF3seWxyJ1kZgaJScV87EJ75hc6vrZxRXYWdSVu8WgjMk19BAsGrVqnaPOzg4sGHDhnbPNY4D+Pr6EhMTYzn+4IMP9nr9RN/LL6tGKYW3i32vXXPLsVzKquv4/SeH+Cg6jaevHEfYILdeu35JVS1/3xDHqp9P4OPiQH55NS9tPs7DF0d0+VoH0ooora5jTpgvNjYKrY1B3knBXgBsPJxFsLczn95+LjY2ivvmhfHZ3nSe2XiUF6+f3OF1o5MLAZgS6oWNjeLXc0fw9eEsDqYVM/gUT887E/N5ZG0MdWbNwbRihjcbtE3KNQLBz0kFVNXW42hndO18ti+dOrPmb1/FMmukLyYbhdaap9bHEujhyOOXt5zN88CFozmaVcoTXx4hzN+VEf6ufBubza2zhzE11As3R1u2xudyyfhAwAgSVbVmDqYWc/5of8t1MooqCfBwxMbG+iv9pUUghJXc/cE+fv3enl67XnFFLcn5Fdw7L4x/XDWexNwyfvVu712/uq6eW97azQc/n+Cmc0PZ9OB5LJk4hLe2J5Peyaft5rYcy8NGwbkjfIkIcAeaBoxr6szsTMxndkOQAPB3d+S2OcP56lAm+1M7nkW+O7mAEB9n/N2M2UKjB7mhlDEr6WRSCyq44/29BPs4Y7JRxOe07KpKyivHzdGW6jqzJdiYzZqNh7Pwc3PgaHYpn+xNA+CrQ5kcSCvm/gtHWQJGIxsbxbPLJjLc14U7Vu1l5TfHqDdrrpsWjK3JhnNH+LA1Pg+tja63NQ3XPFHQctVwRlElgz36Zgq5BAIhrMBs1hxILSI6uYDiyu51rbQWk1EMwIShnlwTNZRfnzeCxLxy8svan6VyMmmFFWw6mmPpl9Za8+jaw0SnFPL8tZN49LJI3BztuH/BKNCw8ptjXf6MrfG5jA/yxMPZjiAvJ1ybDRjvO1FIeU09s8NaLhBdMWc4vq72PLU+tt0FaFpr9qQUEhXibTnmZG9imI9Lh4PRYPTxr3h3D7X1Zl6/MYoQH2eO5zR1DdWbNSn5FVwxcQh2JmUZ5N6fVkRmcRUPLwpnQpAHz357jNKqWv658SjhAW5cObn9PJlujna8dmMUWsOH0anMGeVHiI8xiWR2mB/pRZUk5ZWz/lAmRRW1uDnacqKgZZdYRlFVn4wPgAQCIawitbCC8pp6zBp2JPROWoCDaUYgGD/EWI0+LsiYr34ovbhL1ykor2H5azu5+a3dXP/6LhJyy3hnRwqrd6dy5/kjuGzCYEvZIC9nbpoZyqf70k75xN1ccWUtB9KKmR3mCxhPyaMD3IhraBFsO56HyUZxzoiW62lcHWy5b/4odiUV8NrWxDbXTcorJ7+8hqhQrxbHIwLd2wxGN/fVoUxiM0tYec1Ehvu5EubvSnyzQJBRVElNvZnIwe5MCfGypHLYcCgTO5Ni/phBPHxxBJnFVSx/bScp+RX8flE4ppN024T6uvCf6ybh4WTHbbObppM3/ptsjc/jvZ0pDPd1YcGYAFLym1oE9WZNVknVKbu6eosEAiF66Lsj2Ww/3vJm33zO/JZO5ofZkZDPd0eyOzx/KL2IEB9nPJyNDYPGNSxcOpTWMhAcTCviq4OZ7V6jtt7Mne/vJbukmrsvGMmh9GIWPbeVJ748wvwIfx64sO20xjvmjsDNwZa/dfCU3ujnpAIeW3eYR9fG8Ps1B6k36xZP/BGBbsRmlaC1Zkt8HhOCPPBwarv50fXTg7lkXCBPb4hj89GcFucau2ymtgoE4QFupORXUFbdflqX6OQC3B1tmRdu9MGH+Rvlq+uM2UCNA9TDfF2YHebHkcwSckur2RCTxayRvrg72jFjuA8XhPsTk17COcN9mDvq1OluZof5sffPF7b4dwjxcSHY25m3dySz90QR100PJtTHmZzSasvspJzSKurNWgKBEKeDrOIq7vpgL098eaTF8bisEmwUzBrpy7ZOBAKtNX/47BAPrjlAbQfTQw+kFltu/mB0Pwz3c+FgqxbB0xviePDj9q/z5Fex7EjM56kl43hgwWh+eGAul04IJCrEi2eXTWx3YNLT2Z775o9ia3wer2xp+5SeV1bN/R/t55pXdvDh7lTWHshgZ1I+44Z4MHFoUy6t8AB3SqvqOJxRwqG0ojbdQo2UUvzz6vGMDnDn7g/2kdBsdk90SgGeznYM9225Mjci0BiDONpBqyA6pZCoUG/L9xc2yJV6syY5z3gKtwQCPxfLE/srPyaQVljJonGBluv84eJwJgV78udLx3R63UJ7rYbZYb4k5pbjYGvDVVOCLOsWGscJGmdADfbsm1XTEgiE6IFnvz1GVa2Zo9mllFQ1jQXEZpYQ6uvChWMGcaKggpT8k0+JPJpdSlJeOUUVtexMzG9zPr+smvSiSsYHtUxfMH6IR4sWQWVNPdHJhVTW1rdJtbJ2fzr/257MrbOGsXSK0bft5+bAymsm8uGvzsHNseOtSW+eGcol4wL5+9dxbIozntLNZs37u1KY968f+eJABnfMHcHeP1/I/kcWsP+RBXxx96wWaREiAo3ZTW/+lIRZN3WRtMfZ3pbXbpyCncmGW9+OtvT/RycXEhXi1SZghTdcu73uq4LyGo7nlDElpKkVMdLfCCSNA8ZJeeW4Otji5+pA5GAPvJzteGt7MiYbxYURg5q9z43P7pjJmMHuHda9Mxq/90vHD8bT2d4yftD4c5JeZCw6lRbBGczV1fghzMjI4Kqrrmq3zNy5c4mOjj7pdZ577jkqKpr6FSWtdd86ll3Kx3tSGR/kgdawN6XQci4uq5SIAHfLL/ypuoc2HMpCKXC0s2FDTNsFTY3jAOOGtMxWOy7Ik6ySKnJKjBvHrqR8ahpaAruTC1qUfX/XCcL8XXloUXgXv9Omp/SIAHfuWb2PDYcyufLl7fzxsxjCA9zYcO9sfrcwHCd7U4fXGN0wc2jd/gzcHGyZMPTkmXeDvJx55RdTKK6s5ZJ/b+PPn8eQmFdOVKh3m7JDPJ1wc2x/9fKelMbupKb3jfBzRSksA8aJeeUM83VBKYXJRnHuSF/qzZpzR/jg1YvTfxvNGeXHpeMDueP8EQCEeLffIgj0kBbBGW/w4MGsWdP9DButA4Gkte6e2nozd67ay5tdXJ369w1xuDjY8tL1kzHZKMsNp6y6jpT8CsID3Bjm68IQTye2xZ98H40NMZlMDfVmfsQgvjmcRX2rxWKNT/1jh7R8Em1sITQOJG+Nz8Pe1oZAD0dLfRrrtO9EIfMiBmFr6t6vvbO9La/eOAV7kw23v7+XtMIKVl4zgdUrZjDS/9RrGVwdbAn2dqbOrJkxwge7TtRjaqg3399/HtdEBfHuTmOBVlSIV5tySikiAtwtg9HNRacUYG+yadGacrQzMdTL2TJgnJRXRqhvU2qYOQ0BfOHYgFPWsTuc7W35z3WTLcnnPJ3tcHOwbREI3B1tT9pK600SCHrBQw89xIsvvmh5/dhjj/HXv/6VefPmMXnyZMaNG8fatWvbvC85OZmxY8cCUFlZybXXXktERARLlixpkWvo9ttvJyoqisjISB599FHASGSXkZHB+eefz/nnnw8Yaa3z8ownz5UrVzJ27FjGjh3Lc889Z/m8iIgIbrvtNiIjI1mwYIHkNMJYrfvVwUze25ly6sINdiXm831cDrfPHUGQlzNjAt0tT+CN/dQRge4opZgd5sv24/kdpoY4nlPGsewyLh4bwMXjAskrq2nzNH8wvZjhfi5tbgyRg92xUVjGCbbF5zEt1JtzhvuwO7nQMri7KzGf2np90u6Yzgjycuatm6dy77wwvr9/LldODupSjp/G7qE5XaiHl4s9T105nk9uP5cHF4yyLEhrLTzQjbis0jYrrqOTCxkX5NFmvn+YvyvHs8uorqsnrbCSYc0CwSXjB3PX+SO5YmLrvbSsQylFsI+zZeZQRlHfzRiCM3Fl8YaHIOtQ714zYBwserrD08uWLeO+++7jzjvvBOCjjz5i48aN3HPPPbi7u5OXl8eMGTNYvHhxh780L7/8Ms7OzsTGxnLw4EEmT25aWfnkk0/i7e1NfX098+bN4+DBg9xzzz2sXLmSTZs24evb8pdqz549vPXWW+zatQutNdOnT+e8887Dy8tL0l238v6uFN7beYJhvi4k5pWTVlhBkNfJk3xtOZbLw58eIsDdkVtmGtMCp4R4sXr3CWrrzZbuicZ+69lhfqzencqBtOIW/dSNvo4xZvgsHBuIu5Ot0T10KJMZw5umVh5KK24z1RKMJ8swfzcOpRWRXVLF0exSrpw8BFdHWz7dl05KfgWhvi5sjc/D0c6m3c/vqvFBnowP6l7LMyLQnY2Hs5nVwUDxyUwJ8Tpp/SMC3SmrTiG9qNKS7rqqtp5DacXcPDO0TfmRg1zZEp9LYm45WsPwZoHA1cG2U4nhelOIj7NltllGUWWfrSEAaRH0ikmTJpGTk0NGRgYHDhzAy8uLgIAA/vCHPzB+/Hjmz59Peno62dkdTw3csmWL5YY8fvx4xo8fbzn30UcfMXnyZCZNmsThw4c5cuRIR5cBYNu2bSxZsgQXFxdcXV258sor2bp1KyDprpvblZjPo2sPM3e0Hy/fYATe1jN8iitqOZJRwpGMEg6kFnHnqr3c+ObPONja8OL1ky1PmVNDvamqNXM4o4TYzBLcHG0tv8jnjvBBqaZMnK1tiMlicrAnAR6OONvbMneUP18fzrI82eaUVJFVUtVixlBz44I8OJRebJn7PivM19IfHt3QPbQ1Ppfpw3zaPBX3tV+eE8qrv5jS4um7t4QHGIH3SLMB40PpxdTUm9sdVxjp50ptvbbkELJGnboi2NuFtMIK6s2ajOJKAvtoxhCciS2Ckzy5W9PVV1/NmjVryMrKYtmyZbz//vvk5uayZ88e7OzsCA0NbTf99KkkJSXxzDPPsHv3bry8vLjpppu6dZ1Gku66yR8/j2GotzPPXzsJd0dbBrk7sDU+j2unBQPGrJgrX/6JhNymGT8OtjY8cOEoVpw3vEWa4cYFTtHJBcRlGgPFja0/Lxd7Jg715I1tSfi5ObB8arBl1suJ/AoOZ5Twx2a5fBaNC+Drw1nsSy1kSoh300KyoPYDwfggD9bsSeOj6FR8Xe0t6Rw8nOyITi7g3BE+JOSWs7zh++pPXi72LIi0Tr/76AAj1URcZikXNXxGYxdbey2JxhxN3zRkGw3t50AQ4uNMbb0mIbeMooraPu0akhZBL1m2bBmrV69mzZo1XH311RQXF+Pv74+dnR2bNm0iJeXk/c9z5syxJK6LiYnh4MGDAJSUlODi4oKHhwfZ2dktEth1lP569uzZfP7551RUVFBeXs5nn33G7Nmze/G77V9xWSUUVdScuuBJVNbUk5BbxhUTh+DhZNfQl+/HTwl5loHa7Qn5JOSWc+f5I/jvDVP47w1T+OHBudw9L6xFEAAY5O7IUG8ndicXEJdVaukWavTsNROJHOzOHz+L4cqXt/P5vnS+PJjBS5uPAy0HJS8I98feZMMb25L48mAG6w5kYKPocMpiY0vh56QCZo40cvfY2CimhHixO7nA0srpaN7+mcLZ3pbQVqkmopMLGeHn0m7iv8YppPtSi/B1tW93cVtfapw51Dh9uC+7hs68FkE/iYyMpLS0lCFDhhAYGMj111/PZZddxrhx44iKiiI8/ORT9m6//XZuvvlmIiIiiIiIYMqUKQBMmDCBSZMmER4eztChQ5k5c6blPStWrGDhwoUMHjyYTZs2WY5PnjyZm266iWnTpgFw6623MmnSpDOiGyi1oILFL/zE0ilBPHXluG5fJyG3DK2NhUWNZof5smZPGjHpxUwY6sl7O1Pwcrbj7gvCOtWlMjXEm68OZVJdZ7YscGoU6uvCB7fN4PP96Tz5VSz3fbjfcm5ysGeLLRzdHO2YF+HP+kNZrD9kPK1OCPLA2b79X9eIQHdsbRR1rVbyRoV68UNcDmsPpOPv5sCoQafeHvF0Fx7gZllLYDYbeYkWdTDzx9XBlsEejmQUV/V7txBg+RloDARnzGCxUmoh8DxgAl7XWj/d6nww8Dbg2VDmoYZdzU5Lhw41DVL7+vqyY8eOdsuVlRlT1kJDQy3pp52cnFi9enW75f/3v/+1e/zuu+/m7rvvtrxufqO///77uf/++1uUb/55cHqmu/7XN0epqTez5VguWutu70rVuFo1zL/p5jhzpDHovu14HgEejnwbm83/zRrW6X71qFBvPt1nbEPY2F/dnFKKJZOCuCgygPTCpi659n7hn102kfsvbJoaHHiSm4KjnYnRAW4czihpMSuocZzgp+P5XDl5iNU2Ph9IIgLd+fpwFs99d4zy6jqKK2vbHR9oNMLfdcAEgsGeTtiZFDsTCyyv+4rVAoFSygS8CFwIpAG7lVLrtNbNRzr/hLGX8ctKqTEY21qGWqtO4vQWk17M5/szCPZ25kRBBYl55Z3aBLw98dllmGyUZUUngK+rA5GD3dlyLJe6em1JHdxZjeMEShn91R1xtrc95R4CjnamLu0zsGBMAD6uDi02ch83xAN7kw019WbmnOHdQo3OHeHDCz8onvvO2OnM1cGWmSPbzrZqFObvxtb4PIb59n9ryWSjCPJyJimvHBsFg9ysvyFNI2u2CKYBx7XWiQBKqdXA5UDzQKCBxja0B5BhxfqI09zfv47D09mOl66fzKUvbGNbfF6LQPD29mQ8ne1YPGGw5em3rLqOt7cnM32Yd4snw/icUkJ9nFukQACjH/2NbYkk55czO8y3SwOII/1c8XCyw9vFvsNuHGu5d35Ym2OOdibGBXmwJ6XQ0to500WFenP0L4toXEmg4KQbuzR2DQ6EFgFAsLcRCAa5O3Z74V93WPOndQiQ2ux1GjC9VZnHgG+UUncDLsD89i6klFoBrAAIDm7/Ca0n3QSipZNlmOwvW47lsjU+jz9fOoaxQzwI9nZma3yuZYvApLxyHl13GDC2IvzrFWOJzynj8S8Ok11SzZxRfrxzyzTL9eJzyhjVzmrY2WG+/PfHBLJLqnl88dgu1dHGRnHLzGE42A2cORjXTQtm1CA3/Prw6bK/dWVHrzmj/DhnuE+bbKb9pXGj+r7sFoL+HyxeDvxPa/0vpdQ5wLtKqbFa6xZLMLXWrwKvAkRFRbW5Szk6OpKfn4+Pj48Egx7SWpOfn4+jY9/NYT6V4zmlPP7FYYK8nLhhhvEgMDvMl8/3pVNbb8bOZMOqXSnY2ih+t3A0L25KYMFzW9AaxgS6M2qQG3tTCqk3a0w2ipo6Myn5FVzSLKtkoykhXjja2eDhZMf8CP8250+lvSfz/rR0SpAlwZxoa4inEx+sGDj7iAd7n3mBIB0Y2ux1UMOx5v4PWAigtd6hlHIEfIEcuiAoKIi0tDRyc0+ez0V0jqOjI0FB/X/zqKyp54Uf4nlta2JDbpZJlmmbs8P8eH/XCfadKGJ8kAcf70ljQeQgVswZwdLJQbzww3FCfZy5YUYIXx3KZGt8HnFZJUQO9iA5v5x6s7ZMH2zO0c7EQwvDu940r6+F/atg6zNgYwtzfgvjrgFTfz9ridNJUyDo2wcxa/6U7gbClFLDMALAtcB1rcqcAOYB/1NKRQCOQJfv5nZ2dgwbNuzUBcVpo67ezBUv/sTR7FKWTg7i4YvD8XVt6t44Z4QPNgq2xeeSVlhBUUUtN0wPAcDH1YHHFkdayjYuJtqTUkjkYA/is40ZQ+0FAoCbZrbzs1RXDW9fBqWZEHkljF0KroMg5whkx8DuN6AwCYZMMYLC57fD1pVw/sMwZgnYDJzuIjFwNY5J9eUaArBiINBa1yml7gI2YkwNfVNrfVgp9QQQrbVeBzwAvKaU+g3GwPFNeiB2UIs+911sDkezS1l5zYR294X1cLJj4lBPtsTnse14HsN9XdrNxQPGL1WghyO7kwu58ZxQ4nNKUYquzTj6/glI3QXB58KO/8BPz7U8HzAOlq+GUQuN17FfwKa/wZpbwP9fcMEfYfTFxpQiIToQ5u/KX64Yy+Lxg09duBdZtd3asCZgfatjjzT7+ggws/X7hHh/VwqDPRy5fOIQqCyChB/ALxwGjbGUmR3mx79/iEdr+NMlER2ODyllrLLd05BuID6njGBv587n3Yn/1rj5T70NLnkGyvMh7kuorQD/McYf11bTM8cshvBLIOZT2PwUrL4OxlwOV78twUB0SCnFL2aE9AmMmXQAACAASURBVPnnSgemGHBSsvIoOB7N42OrMH34unEjNtcCyuiSmfsw+I5kdpgvz38fj33Ddn8nMzXUmy8PZpJeVMnx7DJGdrY1UJoFn/0a/CNhwV+MYy4+MOWXp36vjQnGXw2RS2DLP+DHv8Ohj2H8NZ37bCH6iAQC0ffq62D1cvAYCnMeBPfBYDZD7DrYtpKhmYf4ysEM8YDbYJj+K6Nb5fh3sOu/cPhTmLCcCbN+i7eLPfPC/fF0PvkuUo2LvXYm5JOYV8bc8E4ssEreBl8/BDXlcNWbYNfNfluTLZz3e0jYBBt+DyMuAJezY16/OD1IIBB9L3UXxH9jfL3vPZh0PaTthqxDmH3CeI0rUQGRrFh6CfiENQ20hs6EGXfAtpWw+w3sDn7ItsjrUOc/dMqPDA9wx9XBls/2pVNbrwk72Y5aqbth018hcTO4BsDS18G/69s7tmBjgsUvwCuzjWBw1Rs9u15PFadD2s9Nr+1dja43jyDpuuopsxkSN0F1Q/I7ZQLvYcbPst3AmZbdnAQC0feOrgeTPazYDDtegj3/A88QWPIq6+rP4amPDvHevOng185Ts6sfLHwKzr0btv4L5z1vQ/w6uHSl0W3UAZONYlKwpyVnf1h7M4YyD8APT0L8RnD2hQVPwtT/635LoDX/cGNa6aYnYdxVMHpR71y3K0qzYeu/YM9bUN9OBld7Nxg6DWY/YARe0TW1lcaMscOftT2nTOAVCnYNCQZt7Y2W4qiL+rSK7VGn2ySdqKgofapN3UXf0lrz2tZEsoqrAbA1KW48J6T9nb60Rr8wmUxTIK8HPwOAQ30ZNTaOaGXL5qM5aOD7+8/r3ArRvHijDz892pjWecm/wLn9JGP//j6eld8eAyDm8YtwdbC11Ikvf2PcHB09YeY9MO1X4GCF/DN1NfDqXChJh19+AYHjT/mWXlGeD9ufh12vGgFg0vUw5eamIFdZBLmxkH3E6KIryza6sM77PQydLq2EzijPgw+WGy2teY8Y3Zlg/HvnJ0BOLOQdM6YXg/F1QQIsfNro/rQypdQerXVUe+ekRSB67GBaMX9bH4eTnQlbG0VpdR0Af2i22YpF7lFUQSIv1s7ls+wTmFrdYJSCP106pvNpAnzD4JaN8NOzsPlpyNwP168BnxFtijZuej7Yw7EpCADsft0IAtN+ZUzzdGx/A5heYWsPy1fBW5fAu1fATV+Bfzv/Tr2lqgS2vwA7XzLGOsZfY9zc2/n3IeQc4+8Ln4DoN2Dbs/DmRcZTbOSVMPE6499btKQ1HPva6PIryzZmhkVe0bJM4IS276sph09ugw2/g/zjMPaqtmWUMlrLrv5WDcYSCESPbYjJwtZGsePhC/B0tmfpy9uJbrX5eiNz3HpsgDj3mex/YEGbpG/dYmpYyRs6xxiEfn0eLHu/TdfGxGBPTDaKkc2zembFwMY/QtgCWPT3vnny9QqFX66Dty6GtxfDzeutc4Otr4NVy+DEdhhzhTHbqjNjHfbORtfblJvhyFqIWQM/PQ87XjTqGtTuQ2Xfythv1Md9sBFI/SPAd3THffBaQ0WBMeOrt2htjAX88FdI3wPew43A3tl/H3sXWPYufPuIMT3551c7LuvkbXyP594Doxf2Tv2bkUAgekRrzYaYTM4d6WuZuRMV4sWbPyVRVVvfZq5+4d7PSTMP5+ZF5/ZOEGgueDrc+h28fw28cznMf9SY+99wc3C2t+X280Y07fRVU2Es+HLyhMtf6tvuD58RRjD43yXGiuWb1xs3kt609RkjCCx5BSZc2/X3O7gaXUiTroeSDHhrkdH1sWKTMagMEPslpO40gkZ7rQxryDpk/P+a66GuqmFqMaBswHsEBIyF8EuNxX32Lsb0401/NcaAJiw3An5PW33JPxkB4MR2Y/bb4v8Y1+5qShEbE1zUMGZU0c7Dk7keChKNFew5saDre1bvDsgYgeiRIxklXPzvrTx15TjLnrjfHsnmtnei+ehX5zBtWFN/fVVhBvbPj+ED5+u57rf/sV6CwMpCo8l9/Ftj+umcB2HSL4xumUbl+fDV/cYT7y8+gxHnW6cup5J9GP53qXHDunk9ePbSvsLJP8Hbl8L4ZbDkv71zzZxYeP1C8A6F6z6C7x6Dgx8a55TJuBGe9zvwsuKCqJxYI3jaOsHNX4H7EONGmX3YOJdzBNKioSzLKOMVArlxRvfKiPNh77vgFghXvAjD53b984vTYd1dxgJH1wDjZ2vyjWA78LO7yhjB2aim3FjA5ORtrHwNGGs0o3vZhphMbBQsGDPIcqwxt8/u5IIWgWDn16uYi2bsBcutmyXWyQtuWAOJPxozdL6630gRMWaxsbr3xK6mPvML/tR/QQBgUKQRiN5Z3NAy2NDx/5PWxmyU/ASIuLTjsYWKAvj0NqML6uJ/9l5d/SOM9RQfLIPnxhn1mfuwcSPc/oKRb+nQxzD/MZj+697Pr5SxH96/GmzsjNaUV6hx3G+08aeR2Wy0UmI+MVoBlz4Hk24Akx1MuhE++5XRopj+a5j3qNEV1tnPX7XM+Lnp7Rll/UxaBGeqDb83Fl9ZKLj8P8YvRC+av/JH/Fwd2qTynfevzYT4uPDmTVMBKK+uI/qpC4k0peP7p6N91w3T2I97YDXEfQU1RsK5LvWZ94W0PcbNyc4RZt0PUbe07O8uz4Mv7jVSWzTyHwNjrzQGcn1GGDfAw58aOY6KTsCt38LgSb1f191vGC2BhU/DkMlNx4vT4asH4NgGCJ1t3IBdG1J52zqc+qnZXG90lbRWX2cMXP/4NLj4wY1rW974u6qmAr5/3Pj98Akzus6Cppz8PUc3GN2Izj5Ga6hZqpPTxclaBBIIzkSpP8MbC2DqrcYsmJw4oz8zY68xd7+Lv0SF5TV4Otu1eYqPzy7lwme38JfLI/nFOaEtzj30yUHWH8pk/yMLsLFRfP/Vh8z6+Q6KxtzAoGXP9+z7667aSmORmMdQo4U00GQehG/+BEk/Gt0XkUuMlNbabNx4q4qNFsy4a4ykdjGfGE++AIETjWmKOUeMALHgrzByXt9/D1obiwS/fhhqSpuOm+xh5IVG4Bq9yOgKa27rSiOAjZxnBLZhs41glnPEuF76HmNWzcX/7HB6cJcl/gif3wElaUYXYuOgs/8Y4wHBxd9YUxLzKaT8ZATV5avBLaB3Pr+PSSA4m9RVw39nG83XO3eCQ8MMmZJM+O9M4wZz6/edWuFYVFHD37+O44OfU1uMATT69/fxPPvdMXY9PA9/95bXW7MnjQc/PsA3v5lDWNqn1H/xG1Jtggi972uUFbqozihJW2DTU5Cxr+nYoDHGyuRBkS3LFqcZ3UUxnxhPzrN/MzDSXhedMFpg5obBzeJUYzymNNNYq3HNOzD8POPckbXw0Y0QNM0YlC5Ja3ktFz9jgPckCwa7raoY9r7TMMZwBHKPGgPQzfmFG4O5M+5oG8BOIxIIziab/maMDVy/BsIubHnu2Dew6mpjvvzF/zjpZT7fl84TXx6huLIWTyc7fFzt2XjfnBatgoXPbcHN0ZaPf31um/cn55Uz75nvWTdmE5GJb7KlfhyZF73CslmRbcqKs4TZbMyy+epByI+Hy5430ne/udAIcL/80mg5pP1sBEHvEcYTel+mvTDXQ2GyERSK02DYeadlN1B7ZLD4bJG01UgfMH5Z2yAAMGqB8VSz8yVjA5UJy9q9THJeOfd9uJ+JQz156spxHEor5nefHCQ6pZCpwR6Qsp3cnat4q/BrHN28Yc1E4xd25Dyji0IpQnQ6ax2fIDIxnu1ei7k7fxk/Te1Bv644/dnYQOgs+L+N8NEvYe2d4OBuTGi4dlVTKzV4hvGnX+poMsZb+moq7AAhgeBMcWKnMaPBZ6QxiNeR+Y8Z87A//7UxnTJySZsi+1OLAHh66TjCA9wJ8XHm6a8OkLzhOaZWroGSdNxwYJvNZM4PcDee4GLWwA9/MebCh85GHfyIUBs7/qDu55PcaVw1Jajlal5x9nL0gOs/hvW/Nbq1ln/QNKgs+oX8Zp4J0vbAe1eBeyDcuO7kg2m2DsaA13tL4ZNbjaZ4+CUtihxMK8bRzsbI2V9fi3PMB/xg/1c8s7OpDZrB4TEPsnyzB39eMhXT9IZxg4oCY0ZLzCew710YOZ+1gx5k1Xd5gJnrp/f9ZhtiADPZwWXPGbmh2pspJPqUVQOBUmoh8DzGVpWva62fbnX+WaBxErcz4K+19rRmnc44JRnw3hJj6fwvvwC3Qad+j4Or8UT27hKjib709Ra5UQ6mFTEu0BXbw2uM3bUKEnH0n8gNabdwzvClfLovncF+cE1Us81gnL2N+eSTbzSSapnsGJtaBN/lMTnYs2k1rxDNSRAYEKw2tUApZQJeBBYBY4DlSqkWoy5a699orSdqrScCLwCfWqs+Z6yDHxkzH677uGsLxhzd4YZPjClxH//SyCWjNXV1dQzJ+IYXS+42FiXZucC1H+B4+2ZqQs7jue/jScgt53cLw7E1dfDjY7IDYMxgd+aM8uOeeZKoTIiBzJotgmnAca11IoBSajVwOXCkg/LLgUetWJ8zU8wnMCQK/EZ1/b1OnkYr4vPbjcRXGfupyzrK86bDlNgOh6v/BxGXW6Yi3jAjhJ+TCogK8WqxkrgjdiYb3rllWtfrJYToU9acbDwESG32Oq3hWBtKqRBgGPBDB+dXKKWilVLRubm5vV7RAaMoFX76N3x8k7GS9FTy4iHrYM/mV9s5wtI3jI1IDn9KXWUJ99XcQc4NmxsWNDX9iCyMDGD5tGD+umSsdVNECCH61EAZLL4WWKN1+6n1tNavAq+CsY6gLyvWJyoKjAU1yVubjg0aayS0OpmYTwHVNvd5V9nYGBtpTFjOM9vK+XZvFiv92/bp29va8NSV43r2WUKIAceaLYJ0YGiz10ENx9pzLfCBFesysB1ZawSBOb+De/YZeVr2vWcswOmI1ka3UMjMLieTqzd3EEt9w9ifXs7YIR6d3xhGCHHas2Yg2A2EKaWGKaXsMW7261oXUkqFA17ADivWZWDL2Gssuz//D8Y8/Mk3QmESpGzr+D05RyDvqJG7pQsyiysZ++hGfojLbnOutt7MkcwSxgdZcYcuIcSAY7VAoLWuA+4CNgKxwEda68NKqSeUUoubFb0WWK1Pt1wXvSl9n5HFsbHfPeIycPAwcqd3JOYTIwf8mMu79FH7ThRRWVvP61uT2pw7mlVKTZ2Z8UEyg1eIs4lVM1NprddrrUdprUdorZ9sOPaI1npdszKPaa0fsmY9BrSaCuPpfnCzdL52TsbeskfWGpustNbYLTT8PHDx7dLHxWWWALA9IZ+E3LIW5w6lFwNIi0CIs0w/pygUZB00tp9rntcdYPIvoL4aDq1pebyuxsilXphspOvtotisUga5O2Bro1i160SLcwfTinF3tCXYu5MbdQghzggSCPpb+l7j7yGtNsYInGD82ft207HsI/D6BcYmHRNvMJLLdVFsZglTQ725aGwAa/akUVXbNFHrUHoR44M8ZWqoEGcZCQT9LWOvsSlGe5tdTPqFkSDucS943BtePgdKs+DaD4w9V5vvwQvU1Zt566ckyqvr2v2okqpa0goriQh05/rpwRRX1vLlwUwACsprOJpVKt1CQpyFBso6grNX+t623UKNJt1gpI+orTRe2znClJs7HBfYmVjA418YC7dvnjmszfljWcaOURGBbpwz3Ifhfi68tzMFs9Y8vSEOs4YLwiULpBBnGwkE/amyEAoSYOJ17Z+3czr1orJmYhsGgjccymo3EDSeDw9wRynF9dND+MuXR9ifWsSUEC/+esVYIgIlOZwQZxsJBP2pcSvC1uMD3RSbZdzod6cUkFNahb+bY6vzpXg42RHoYRy/OiqIXYn5zIvw5+opQ2URmRBnKRkj6E+NA8WDJ/XK5WIzSwn2dkZr2Hi47YKx2MwSwgPcLIPB7o52vHpjFMumBksQEOIsJoGgPzXuy+rU8wVctfVmjueUsmhcAMP9XNhwKLPFebNZczSrVLp+hBBtSCDoT+l7Oh4o7qLE3HJq6zVjAt25eGwgu5IKyC+rtpxPLaygoqaeiEC3Xvk8IcSZQwJBfynJhNLM3hsfaDYQvGhcAPVmzbdHsts9L4QQzUkg6A9aw9Z/GV8H9c7GLbFZJdibbBju58KYQHeCvZ1ZH5PVdD6zFBsFowZJi0AI0ZIEgr6mNXz7Z9j9Gsy4s9e6hmIzSxnp74qdyQalFIvGBbD9eB5FFTUAxGWVEOrrgpO97BErhGhJAkFf2/QkbH8Bpt4GFz3ZlHG0h+IyS1oMBF82fjB1Zs3Sl7ezIyGf2MxSIqRbSAjRDgkEfcVcD1//Abb809hvYNE/uh0EquvqWX8ok+o6I09Qflk1OaXVLQaCxw7x4K2bp1JTb2b5azs5UVBBeIB0Cwkh2pJA0BdqyuHDX8DOF2H6r+HS51vsBdwVWmv+9FkMd7y/l1d+TAQgriF1ROuB4PNH+/PNfedx1/kjcXO0ZVZY11JWCyHODrKy2NoqC+GdK4x004v+CdNX9Ohyb/2UzMd70vB1teeVHxO4bnqwZUZQe1NDnexNPHjRaB68aHSPPlcIceaSFoG17V8Fmfth2fs9DgLb4vN4cn0sC8YMYvWKc6iqM/Pv7+OJyyrFz80BH1eHXqq0EOJsYtVAoJRaqJQ6qpQ6rpRqdxcypdQ1SqkjSqnDSqlV1qxPv4j/BvzCIfziHl0mp7SKO1ftZYSfCyuXTWSkvyvXTh3Kql0n2BafJyuGhRDdZrVAoJQyAS8Ci4AxwHKl1JhWZcKAh4GZWutI4D5r1adfVJdC8k8QdmGPL7UjIZ/iylr+cdUEXB2MHr1754dhb2tDVkkVETIQLIToJmu2CKYBx7XWiVrrGmA10Hqn9duAF7XWhQBa6xwr1qfvJf4I5loIu6jHl4rNLMXOpBjT7Mnf382R22YPByBcUkcIIbrJmoPFQ4DUZq/TgOmtyowCUEr9BJiAx7TWX7e+kFJqBbACIDg42CqVtYr4jeDgDsEzenypuKwSRvq7YW/bMnb/+rwR2JkUC8a0s8OZEEJ0Qn8PFtsCYcBcYDnwmlKqTSpOrfWrWusorXWUn59fH1exm7SG+G9hxPlgsuvx5WIzS9rt/nGyN3HXBWG4OMgEMCFE91gzEKQDQ5u9Dmo41lwasE5rXau1TgKOYQSG01/WISOpXC90CxWU15BdUi3dP0IIq7BmINgNhCmlhiml7IFrgXWtynyO0RpAKeWL0VWUaMU69Z34b4y/R87v8aXishrXCcjMICFE77NaINBa1wF3ARuBWOAjrfVhpdQTSqnFDcU2AvlKqSPAJuC3Wut8a9WpT8V/Y+w85jaox5eKzWx/5bAQQvQGq3Ysa63XA+tbHXuk2dcauL/hz5mjogDSdsOc3/bK5eIyS/B1dcDPTRaMCSF6X38PFp+ZEn4AbYawBb1yudisEtlZTAhhNRIIrCFpCzh49Mqm9HX1Zo5ll0nmUCGE1UggsIbkbRByLtj0fBOY5PxyaurMMlAshLAaCQS9rSQDChJg2OxeudwRGSgWQliZBILelrTV+Du0dwJBXGYJtjaKEf4uvXI9IYRoTQJBb0veAo6eMGhsr1wuLsvYi9jBVvYaFkJYhwSC3pa0FUJndXsHsh+P5TL9b9/x/HfxVNfVE5tZIgPFQgirkgQ1vanoBBSlwIw7uvX2hNwy7lq1F5ON4tnvjvHZvjQyi6tkoFgIYVXSIuhNyduMv7sxUFxSVctt70Rjb7Lhy7tn8c4t0yznxg7x6K0aCiFEG51qESillgA/aK2LG157AnO11p9bs3KnnaSt4OwDfhFdelu9WXPvB/s4kV/B+7dOJ8jLmSAvZ76+bw77ThQxY7i3lSoshBCdbxE82hgEALTWRcCj1qnSaUprSO7e+MA/Nsax6Wgujy2OZPpwH8txRzsT54zwQSnV27UVQgiLzt6x2isn4wvNFSZDcWqXp42u3Z/OKz8mcv30YG6YEWKdugkhxEl0NhBEK6VWKqVGNPxZCeyxZsVOO6k/G3+HzOz0Ww6mFfG7NQeZNsybRy+LtFLFhBDi5DobCO4GaoAPMfYergLutFalTkv58aBM4DOyU8ULy2v41bt78HV14OXrJ7fZglIIIfpKp7p3tNblwENWrsvpLT8BPIPB1r5TxX9KyCOzuIrVK2bg4yrppYUQ/adTj6FKqW+b7yWslPJSSm20XrVOQwUJ4DOi08WziqsA2XVMCNH/Otsf4dswUwgArXUh4G+dKp2GtDZaBN6dDwSZxVU425twd5QxdyFE/+psIDArpYIbXyilQgF9qjcppRYqpY4qpY4rpdp0LSmlblJK5Sql9jf8ubWzFR9QynKgpqzT4wNgtAgCPBxlaqgQot919nH0j8A2pdSPgAJmAytO9gallAl4EbgQSAN2K6XWaa2PtCr6odb6rq5Ve4ApSDD+9hne6bdkFlcS6OFopQoJIUTndapFoLX+GogCjgIfAA8Alad42zTguNY6UWtdgzHb6PIe1HXgym8IBF3oGsoqriLA3clKFRJCiM7rbIqJW4F7gSBgPzAD2AFccJK3DQFSm71OA6a3U26pUmoOcAz4jdY6tXUBpdQKGlogwcHBrU/3v/zjYGMHHkM7VbzerMkurZYWgRBiQOjsGMG9wFQgRWt9PjAJKDr5WzrlCyBUaz0e+BZ4u71CWutXtdZRWusoPz+/XvjYXlaQAN7DwNS5nrb8smrqzZpBEgiEEANAZwNBlda6CkAp5aC1jgNGn+I96UDzR+SghmMWWut8rXV1w8vXgSmdrM/Akp/Y5RlDAIHuEgiEEP2vs4EgrWEdwefAt0qptUDKKd6zGwhTSg1TStkD1wLrmhdQSgU2e7kYiO1kfQYOs7nLawgaA0GAtAiEEANAZ1cWL2n48jGl1CbAA/j6FO+pU0rdBWwETMCbWuvDSqkngGit9TrgHqXUYqAOKABu6t630Y9KM6CuqouLyYxxdhkjEEIMBF1ezaS1/rELZdcD61sde6TZ1w8DD3e1DgNKN2YMZZZUYW+ywdulc+kohBDCmiTTWU9Z1hB0ceqoLCYTQgwQEgh6Kj8BbB3BbXCn35JZXEWADBQLIQYICQQ91ZhjqAu7kjW2CIQQYiCQQNBTBQldSi2htSarpEoGioUQA4YEgp4w10NBUpcGigsraqmpM0uLQAgxYEgg6ImiE2Cu7eIaApk6KoQYWCQQ9IRlxlDX0k8DDJLBYiHEACGBoCeKThh/e4Z0+i2W9BIeknlUCDEwSCDoibIcQIFr5zdryyquwmSj8HOTfYqFEAODBIKeKMsGZx8w2XX6LZnFVfi7OWCykcVkQoiBQQJBT5Rmg+ugLr0lu0TWEAghBhYJBD1Rlt2lbiGQLSqFEAOPBIKeKMsGt4BOF9dak1lcJTOGhBADigSC7tK6wxZBWmEFD3x0gPyy6hbHS6vrqKiplxaBEGJAkUDQXZWFUF8Drm1bBD/E5fDJ3jRuf38vNXVmy/Esy4Y0MnVUCDFwSCDorrIc4+92WgSJueXYKPg5qYAnvjwMQF29mbX7jZ06JfOoEGIg6fLGNF2hlFoIPI+xQ9nrWuunOyi3FFgDTNVaR1uzTr2mLMv4u50xgqS8csYMdmfmSF9e+TERFwdbthzLIzazhHnh/kwK9uzjygohRMesFgiUUibgReBCIA3YrZRap7U+0qqcG3AvsMtadbEKS4ug7fTRpLxyxgd58LuLwjmWVcorPyYS4O7Iy9dPZuHYANmQRggxoFizRTANOK61TgRQSq0GLgeOtCr3F+DvwG+tWJfeV9rQImgVCKrr6kkrrOCKiYMx2SheuG4yGw5lsmhcIK4OVm2ACSFEt1hzjGAIkNrsdVrDMQul1GRgqNb6KyvWwzrKssHWCRzcWhxOLajArGGYnwsArg62XB01VIKAEGLA6rfBYqWUDbASeKATZVcopaKVUtG5ubnWr1xnlGWj3QaxN7WoxeHE3HIAhvm69kethBCiy6wZCNKBoc1eBzUca+QGjAU2K6WSgRnAOqVUVOsLaa1f1VpHaa2j/Pz8rFjlLijLJh9PrnxpO8eySy2Hk/MbAoGPS3/VTAghusSagWA3EKaUGqaUsgeuBdY1ntRaF2utfbXWoVrrUGAnsPj0mTWUQ1a9BwC7kgosh5PyyvFxscfDufOJ6IQQoj9ZLRBoreuAu4CNQCzwkdb6sFLqCaXUYmt9bp8pzSKp2uj+iU5uCgSJueUM85XWgBDi9GHVEUyt9Xpgfatjj3RQdq4169Kr6qqhqoj4OmcAopMLLaeS8so5b9QA6b4SQohOkJXF3VGWDUCW9mT6MG/SiyrJKKqkrLqOnNJqy4whIYQ4HUgg6I6GxWS52pNbZg0DIDqlkOQ8Y6B4uHQNCSFOIzK5vTsaFpPVOPkxL9wfZ3tTi3ECmToqhDidSCDojoauIf+AodiabJgc7EV0ciE+Lg4oBSE+zv1cQSGE6DzpGuqG2uJMzFoRHBIKwJQQL+KySjiYVsRgDycc7Uz9W0EhhOgCCQTdUJiTRj5ujAvyAWBqqDdmDT8ey2W4DBQLIU4z0jXUDZUFGVRoT8YHGQvKJgZ7YrJR1Jk1obKiWAhxmpEWQXeUZVNk8sa/YYMZVwdbIgKN5HOymEwIcbqRQNANTtW5aJeWO5NFhXgDyBoCIcRpRwJBF5VWVuNpLsLec3CL4/MjBuFkZyIy0L2faiaEEN0jgaCLYpNOYK/q8fBvsbUCs8J8iXn8Ikt3kRBCnC4kEHRR2olkAAYNDm1zzmQjW1AKIU4/Egi6qCDb2HTN3XfIKUoKIcTpQQJBF5nzjhtfuAX0b0WEEKKXSCDoAl1fx/zSz8l0HAFew/q7OkII0SskEHRB6b5PGU46cWErwEb+6YQQZwa5m3WW2Yxp2zMcNw/GbuyS/q6NEEL0GqsGAqXUQqXUUaXUcaXUQ+2c6DUUKwAADExJREFU/7VS6pBSar9SaptSaow169MVZrOmuKK26cCxr3EpOsqLdZczMsCj/yomhBC9zGqBQCllAl4EFgFjgOXt3OhXaa3Haa0nAv8AVlqrPl1xOKOYK1/ezvSnviOnpAq0hi3/oMB+MJvs5jDI3aG/qyiEEL3GmknnpgHHtdaJAEqp1cDlwJHGAlrrkmblXQBttdrsfQe2v3DSImatyS+vwaGilpU2CrPSOL7qCPYKChL42ONehnl6oJSsFxBCnDmsGQiGAKnNXqcB01sXUkrdCdwP2AMXtHchpdQKYAVAcHBw92rj7AuDIk9aJDm3nCPlJQR7OxMe4MbmY7mUKAcmB3rCiAt4a+85zBkqu48JIc4s/Z6GWmv9IvCiUuo64E/AL9sp8yrwKkBUVFT3Wg3hFxt/TuJvb0eT4FHGpt/MBWDDh/vZciyX3UvnU1xZS9bWbxnpL4FACHFmseZgcTowtNnroIZjHVkNXGHF+pyU1po9KQVEhXhZjs0a6Ut+eQ2xWSUczy0DIMzfrb+qKIQQVmHNQLAbCFNKDVNK2QPXAuuaF1BKhTV7eQkQb8X6nFRCbjmFFbVEhTYFgtlhvgBsjc8jPtsIBNIiEEKcaazWNaS1rlNK3QVsBEzAm1rrw0qpJ4BorfU64C6l1HygFiiknW6hvhKdXABAVKi35Zi/uyOjB7mxLT6PsEGuONmZGOLp1F9VFEIIq7DqGIHWej2wvtWxR5p9fa81P78rolMK8XaxZ3irHcZmh/ny/+3dbYwV1R3H8e+P5VGgPBVZBQKolBaNggKxWo1RY9Q2wAuNWrW2MeGNpto2aTW2NrWvWptqmxgL0bbQ+ky1JYZqKzU2vkBYFK2AVrSoqzysCruo7MKy/76YufayD0phZ+8y5/dJNtw5M9x7DmfZ386ZmXOWrX6Ttvb9HH/0cAZ4hlEzKxk/WZxr2PIBp00Z0+XW0LO+MJ697R2s3bLT1wfMrJQcBEDT7ja2vP8xc6uuD1TMmzqWwXXZP5OvD5hZGTkIgHVvZtcHTpsytsu+YYPrmDstC4jpDgIzKyEHAbB2y06GDBzASRO7X2/47OnjAZhR76EhMyufmj9Q1h80bPmAUyaPZsjAum73X3PGVGbUj2TKuOHd7jczO5Ilf0bw8d52NrzbcsCDZJ0NHVTHOTOO7sNamZn1neSD4IW3dtHeEcyd2vX6gJlZCpIdGtrfEdy/5i1uf+IVRg4ZyKmfckZgZlZmSQbB9pZWFi1r4MXGZs44fhw/XXgSo4YNqnW1zMxqIskgWL6ukRcbm7nzslksmHWs1xcws6QlGQTv7trD2OGDWTh7Yq2rYmZWc0leLN7W3Er954bWuhpmZv1CkkGwtbmVY0Y5CMzMINEg2N7SSr2DwMwMSDAIWvft5/2P9npoyMwsl1wQ7GhpA/AZgZlZLrkg2Nq8B4BjRnmlMTMzKDgIJF0o6VVJmyXd1M3+70raKOklSaskTSmyPgDbWloBnxGYmVUUFgSS6oC7gIuAmcAVkmZ2OuwFYE5EnAwsB35eVH0qtjY7CMzMqhV5RjAP2BwRb0TEXuBBYEH1ARHxdER8nG+uBiYVWB8ge4Zg5NCBjBiS5LN0ZmZdFBkEE4G3q7Yb87KeXAv8tbsdkhZJapDU0NTUdFiV2tq8x3cMmZlV6RcXiyVdBcwBbu9uf0QsiYg5ETFn/Pjxh/VZ21raPCxkZlalyCB4B5hctT0pLzuApPOBW4D5EdFWYH0A2Na8x08Vm5lVKTII1gLTJU2TNBi4HFhRfYCk2cBishDYUWBdANi3v4Mdu9uo962jZmafKCwIIqIduB54EtgEPBwRGyTdJml+ftjtwAjgEUnrJa3o4e16RdPuNiLwGYGZWZVCb52JiJXAyk5lt1a9Pr/Iz+/Mt46amXXVLy4W95VtlSDwXUNmZp9IKgj+N72Eg8DMrCKpINje0srQQQO8PrGZWZWkgiBbkGaY1yg2M6uSVBB4iUozs66SCgIvUWlm1lUyQdDREWxvaWWCg8DM7ADJBMF7H7XR3hE+IzAz6ySZIPAzBGZm3UsmCCpPFXuJSjOzAyUTBNu9RKWZWbeSCYL6zw3lgpkTGDd8cK2rYmbWrySzXuMFJ9ZzwYn1ta6GmVm/k8wZgZmZdc9BYGaWOAeBmVniHARmZokrNAgkXSjpVUmbJd3Uzf6zJT0vqV3SJUXWxczMuldYEEiqA+4CLgJmAldImtnpsLeAbwL3F1UPMzP7dEXePjoP2BwRbwBIehBYAGysHBARW/J9HQXWw8zMPkWRQ0MTgberthvzsv+bpEWSGiQ1NDU19UrlzMwsc0Q8UBYRS4AlAJKaJL15iG/1eeC9XqvYkSG1Nru95ZZae6H32jylpx1FBsE7wOSq7Ul52WGJiPGH+nclNUTEnMOtw5EktTa7veWWWnuhb9pc5NDQWmC6pGmSBgOXAysK/DwzMzsEhQVBRLQD1wNPApuAhyNig6TbJM0HkDRXUiNwKbBY0oai6mNmZt0r9BpBRKwEVnYqu7Xq9VqyIaO+sqQPP6u/SK3Nbm+5pdZe6IM2KyKK/gwzM+vHPMWEmVniHARmZolLJgg+a96jI52kyZKelrRR0gZJN+TlYyX9XdJr+Z9jal3X3iSpTtILkh7Pt6dJei7v54fyO9ZKQ9JoScslvSJpk6Qvl7mPJX0n/35+WdIDkoaWqY8l/VbSDkkvV5V125/K/Dpv90uSTu2teiQRBAc579GRrh34XkTMBE4HrsvbeBOwKiKmA6vy7TK5geyutIqfAXdExAnATuDamtSqOL8CnoiILwKnkLW9lH0saSLwbWBORJwE1JHdhl6mPv49cGGnsp768yJgev61CLi7tyqRRBBQNe9RROwFKvMelUZEbI2I5/PXu8l+QEwka+fS/LClwMLa1LD3SZoEfBW4J98WcC6wPD+kbO0dBZwN3AsQEXsjYhcl7mOyOxuHSRoIHAVspUR9HBH/BD7oVNxTfy4AlkVmNTBa0jG9UY9UgqDX5j06EkiaCswGngMmRMTWfNc2YEKNqlWEO4HvA5VJC8cBu/JnWKB8/TwNaAJ+lw+H3SNpOCXt44h4B/gF2SzFW4FmYB3l7mPouT8L+zmWShAkQ9II4E/AjRHRUr0vsnuFS3G/sKSvATsiYl2t69KHBgKnAndHxGzgIzoNA5Wsj8eQ/RY8DTgWGE7XYZRS66v+TCUICpn3qL+RNIgsBO6LiEfz4u2V08f8zx21ql8vOxOYL2kL2VDfuWTj56PzYQQoXz83Ao0R8Vy+vZwsGMrax+cD/4mIpojYBzxK1u9l7mPouT8L+zmWShCUft6jfHz8XmBTRPyyatcK4Jr89TXAX/q6bkWIiJsjYlJETCXrz39ExJXA00BltbvStBcgIrYBb0uakRedR7a+Ryn7mGxI6HRJR+Xf35X2lraPcz315wrgG/ndQ6cDzVVDSIcnIpL4Ai4G/g28DtxS6/oU0L6vkJ1CvgSsz78uJhs3XwW8BjwFjK11XQto+znA4/nr44A1wGbgEWBIrevXy22dBTTk/fxnYEyZ+xj4CfAK8DLwB2BImfoYeIDs+sc+sjO+a3vqT0Bkdz++DvyL7G6qXqmHp5gwM0tcKkNDZmbWAweBmVniHARmZolzEJiZJc5BYGaWOAeBWR+SdE5lplSz/sJBYGaWOAeBWTckXSVpjaT1khbn6x58KOmOfH78VZLG58fOkrQ6nyP+sar540+Q9JSkFyU9L+n4/O1HVK0pcF/+1KxZzTgIzDqR9CXgMuDMiJgF7AeuJJv0rCEiTgSeAX6c/5VlwA8i4mSyJz4r5fcBd0XEKcAZZE+QQjYz7I1ka2McRzZ/jlnNDPzsQ8yScx5wGrA2/2V9GNnEXx3AQ/kxfwQezdcIGB0Rz+TlS4FHJI0EJkbEYwAR0QqQv9+aiGjMt9cDU4Fni2+WWfccBGZdCVgaETcfUCj9qNNxhzo/S1vV6/34/6HVmIeGzLpaBVwi6Wj4ZA3ZKWT/XyqzXn4deDYimoGdks7Ky68GnolslbhGSQvz9xgi6ag+bYXZQfJvImadRMRGST8E/iZpANnMkNeRLQQzL9+3g+w6AmRTBf8m/0H/BvCtvPxqYLGk2/L3uLQPm2F20Dz7qNlBkvRhRIyodT3MepuHhszMEuczAjOzxPmMwMwscQ4CM7PEOQjMzBLnIDAzS5yDwMwscf8F6Tou840MnE0AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_history(history)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Test Set Metrics:\n",
      "\tloss: 1.0698\n",
      "\tacc: 0.7911\n"
     ]
    }
   ],
   "source": [
    "appnp_model.load_weights(\"logs/best_appnp_model.h5\")\n",
    "test_metrics = appnp_model.evaluate_generator(test_gen)\n",
    "print(\"\\nTest Set Metrics:\")\n",
    "for name, val in zip(appnp_model.metrics_names, test_metrics):\n",
    "    print(\"\\t{}: {:0.4f}\".format(name, val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Scalable APPNP Training\n",
    "\n",
    "Now we're going to exploit the structure of PPNP for scalable training. PPNP consists of a fully-connected neural network followed by a graph propogation step. For each node, the fully-connected network outputs a score for each class and the propogaiton step basically takes a weighted average of scores of nearby nodes (closer nodes are weighted higher). \n",
    "\n",
    "Above, we trained the whole network end-to-end which obtains the most accurate results but  requires us to load the entire graph onto our GPU memory. This is because we need the entire graph for the propogation step. Unfortunately, this limits the graph size by our GPU memory. To get around this, we can train the fully-connected network separately and once we have a trained fully connected network we can add the graph propagation step.  The advantage of this approach is that we can train on batches of node features instead of the entire graph.\n",
    "\n",
    "The model in the propagation step can be any keras model trained on node features to predict the target classes. In this example we use a fully connected neural network with bag of word features as input. We could easily swap out the bag of words features for the complete text and replace the fully connected network with a state-of-the-art NLP model (for example BERT [1]), fine-tune the model and propagate its predictions.\n",
    "\n",
    "\n",
    "<br>\n",
    "\n",
    "1. Devlin, J., Chang, M. W., Lee, K., & Toutanova, K. (2018). Bert: Pre-training of deep bidirectional transformers for language understanding. https://arxiv.org/abs/1810.04805"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First we create and train a fully connected model."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = keras.models.Model()\n",
    "\n",
    "in_layer = layers.Input(shape=(len(feature_names),))\n",
    "\n",
    "layer = layers.Dropout(0.5)(in_layer)\n",
    "layer = layers.Dense(64, activation=\"relu\", kernel_regularizer=\"l2\")(layer)\n",
    "layer = layers.Dropout(0.5)(layer)\n",
    "layer = layers.Dense(64, activation=\"relu\", kernel_regularizer=\"l2\")(layer)\n",
    "layer = layers.Dropout(0.5)(layer)\n",
    "\n",
    "# note the dimension of the output should equal the number of classes to predict!\n",
    "layer = layers.Dense(train_targets.shape[-1], activation=\"relu\")(layer)\n",
    "layer = layers.Softmax()(layer)\n",
    "\n",
    "fully_connected_model = keras.models.Model(inputs=in_layer, outputs=layer)\n",
    "\n",
    "fully_connected_model.compile(\n",
    "    loss=\"categorical_crossentropy\", metrics=[\"acc\"], optimizer=optimizers.Adam(lr=0.01)\n",
    ")\n",
    "\n",
    "# the inputs are just the node features\n",
    "X_train = train_data[feature_names].values.astype(np.float32)\n",
    "X_val = val_data[feature_names].values.astype(np.float32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 140 samples, validate on 500 samples\n",
      "Epoch 1/2000\n",
      "140/140 [==============================] - 1s 5ms/sample - loss: 3.7968 - acc: 0.2000 - val_loss: 3.2773 - val_acc: 0.3060\n",
      "Epoch 2/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 3.2678 - acc: 0.2571 - val_loss: 2.9255 - val_acc: 0.3020\n",
      "Epoch 3/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 2.8700 - acc: 0.3286 - val_loss: 2.6927 - val_acc: 0.3020\n",
      "Epoch 4/2000\n",
      "140/140 [==============================] - 0s 129us/sample - loss: 2.6667 - acc: 0.3000 - val_loss: 2.5439 - val_acc: 0.3020\n",
      "Epoch 5/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 2.4381 - acc: 0.3357 - val_loss: 2.4525 - val_acc: 0.3020\n",
      "Epoch 6/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 2.3156 - acc: 0.3571 - val_loss: 2.3959 - val_acc: 0.3020\n",
      "Epoch 7/2000\n",
      "140/140 [==============================] - 0s 177us/sample - loss: 2.2424 - acc: 0.3786 - val_loss: 2.3614 - val_acc: 0.3140\n",
      "Epoch 8/2000\n",
      "140/140 [==============================] - 0s 180us/sample - loss: 2.1720 - acc: 0.4357 - val_loss: 2.3360 - val_acc: 0.3360\n",
      "Epoch 9/2000\n",
      "140/140 [==============================] - 0s 179us/sample - loss: 2.1291 - acc: 0.4643 - val_loss: 2.3128 - val_acc: 0.3980\n",
      "Epoch 10/2000\n",
      "140/140 [==============================] - 0s 177us/sample - loss: 2.0582 - acc: 0.5286 - val_loss: 2.2871 - val_acc: 0.4200\n",
      "Epoch 11/2000\n",
      "140/140 [==============================] - 0s 181us/sample - loss: 1.9274 - acc: 0.6000 - val_loss: 2.2565 - val_acc: 0.4340\n",
      "Epoch 12/2000\n",
      "140/140 [==============================] - 0s 180us/sample - loss: 1.8448 - acc: 0.5714 - val_loss: 2.2208 - val_acc: 0.4460\n",
      "Epoch 13/2000\n",
      "140/140 [==============================] - 0s 180us/sample - loss: 1.8578 - acc: 0.6214 - val_loss: 2.1854 - val_acc: 0.4540\n",
      "Epoch 14/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 1.7390 - acc: 0.6357 - val_loss: 2.1567 - val_acc: 0.4540\n",
      "Epoch 15/2000\n",
      "140/140 [==============================] - 0s 177us/sample - loss: 1.6419 - acc: 0.6429 - val_loss: 2.1330 - val_acc: 0.4660\n",
      "Epoch 16/2000\n",
      "140/140 [==============================] - 0s 178us/sample - loss: 1.6125 - acc: 0.6500 - val_loss: 2.1103 - val_acc: 0.4680\n",
      "Epoch 17/2000\n",
      "140/140 [==============================] - 0s 176us/sample - loss: 1.5577 - acc: 0.7071 - val_loss: 2.0861 - val_acc: 0.4720\n",
      "Epoch 18/2000\n",
      "140/140 [==============================] - 0s 178us/sample - loss: 1.4410 - acc: 0.7143 - val_loss: 2.0673 - val_acc: 0.4800\n",
      "Epoch 19/2000\n",
      "140/140 [==============================] - 0s 177us/sample - loss: 1.3676 - acc: 0.7571 - val_loss: 2.0597 - val_acc: 0.5060\n",
      "Epoch 20/2000\n",
      "140/140 [==============================] - 0s 186us/sample - loss: 1.3642 - acc: 0.7214 - val_loss: 2.0573 - val_acc: 0.5180\n",
      "Epoch 21/2000\n",
      "140/140 [==============================] - 0s 178us/sample - loss: 1.2922 - acc: 0.7786 - val_loss: 2.0559 - val_acc: 0.5200\n",
      "Epoch 22/2000\n",
      "140/140 [==============================] - 0s 129us/sample - loss: 1.3678 - acc: 0.7500 - val_loss: 2.0534 - val_acc: 0.5100\n",
      "Epoch 23/2000\n",
      "140/140 [==============================] - 0s 130us/sample - loss: 1.2351 - acc: 0.8214 - val_loss: 2.0520 - val_acc: 0.5140\n",
      "Epoch 24/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 1.2904 - acc: 0.7857 - val_loss: 2.0488 - val_acc: 0.5160\n",
      "Epoch 25/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 1.2203 - acc: 0.8000 - val_loss: 2.0458 - val_acc: 0.5180\n",
      "Epoch 26/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 1.2768 - acc: 0.7786 - val_loss: 2.0307 - val_acc: 0.5160\n",
      "Epoch 27/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 1.1932 - acc: 0.8071 - val_loss: 2.0132 - val_acc: 0.5200\n",
      "Epoch 28/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 1.1916 - acc: 0.8143 - val_loss: 2.0049 - val_acc: 0.5200\n",
      "Epoch 29/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 1.1778 - acc: 0.8143 - val_loss: 1.9966 - val_acc: 0.5160\n",
      "Epoch 30/2000\n",
      "140/140 [==============================] - 0s 178us/sample - loss: 1.1542 - acc: 0.8214 - val_loss: 1.9867 - val_acc: 0.5220\n",
      "Epoch 31/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 1.1275 - acc: 0.8143 - val_loss: 1.9808 - val_acc: 0.5160\n",
      "Epoch 32/2000\n",
      "140/140 [==============================] - 0s 178us/sample - loss: 1.1113 - acc: 0.8500 - val_loss: 1.9804 - val_acc: 0.5260\n",
      "Epoch 33/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 1.0406 - acc: 0.8714 - val_loss: 1.9793 - val_acc: 0.5240\n",
      "Epoch 34/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 1.1404 - acc: 0.8143 - val_loss: 1.9743 - val_acc: 0.5220\n",
      "Epoch 35/2000\n",
      "140/140 [==============================] - 0s 185us/sample - loss: 1.0901 - acc: 0.8500 - val_loss: 1.9624 - val_acc: 0.5380\n",
      "Epoch 36/2000\n",
      "140/140 [==============================] - 0s 131us/sample - loss: 1.1520 - acc: 0.8143 - val_loss: 1.9597 - val_acc: 0.5360\n",
      "Epoch 37/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 1.0779 - acc: 0.8500 - val_loss: 1.9548 - val_acc: 0.5380\n",
      "Epoch 38/2000\n",
      "140/140 [==============================] - 0s 131us/sample - loss: 1.0880 - acc: 0.8429 - val_loss: 1.9497 - val_acc: 0.5320\n",
      "Epoch 39/2000\n",
      "140/140 [==============================] - 0s 136us/sample - loss: 1.0261 - acc: 0.8643 - val_loss: 1.9436 - val_acc: 0.5380\n",
      "Epoch 40/2000\n",
      "140/140 [==============================] - 0s 130us/sample - loss: 1.0328 - acc: 0.8857 - val_loss: 1.9446 - val_acc: 0.5220\n",
      "Epoch 41/2000\n",
      "140/140 [==============================] - 0s 129us/sample - loss: 1.0047 - acc: 0.8786 - val_loss: 1.9475 - val_acc: 0.5200\n",
      "Epoch 42/2000\n",
      "140/140 [==============================] - 0s 130us/sample - loss: 1.0867 - acc: 0.8500 - val_loss: 1.9558 - val_acc: 0.5220\n",
      "Epoch 43/2000\n",
      "140/140 [==============================] - 0s 132us/sample - loss: 1.0356 - acc: 0.8571 - val_loss: 1.9640 - val_acc: 0.5200\n",
      "Epoch 44/2000\n",
      "140/140 [==============================] - 0s 143us/sample - loss: 1.0010 - acc: 0.8714 - val_loss: 1.9628 - val_acc: 0.5240\n",
      "Epoch 45/2000\n",
      "140/140 [==============================] - 0s 135us/sample - loss: 0.9672 - acc: 0.8714 - val_loss: 1.9520 - val_acc: 0.5260\n",
      "Epoch 46/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 1.0804 - acc: 0.8286 - val_loss: 1.9513 - val_acc: 0.5120\n",
      "Epoch 47/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 0.9792 - acc: 0.8857 - val_loss: 1.9612 - val_acc: 0.5160\n",
      "Epoch 48/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 1.0355 - acc: 0.8571 - val_loss: 1.9671 - val_acc: 0.5060\n",
      "Epoch 49/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 1.1057 - acc: 0.8143 - val_loss: 1.9631 - val_acc: 0.5060\n",
      "Epoch 50/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 1.0471 - acc: 0.8500 - val_loss: 1.9458 - val_acc: 0.4980\n",
      "Epoch 51/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 1.0250 - acc: 0.8643 - val_loss: 1.9394 - val_acc: 0.5020\n",
      "Epoch 52/2000\n",
      "140/140 [==============================] - 0s 121us/sample - loss: 1.0530 - acc: 0.8429 - val_loss: 1.9348 - val_acc: 0.5180\n",
      "Epoch 53/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 0.9798 - acc: 0.8929 - val_loss: 1.9337 - val_acc: 0.5240\n",
      "Epoch 54/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 1.0195 - acc: 0.8714 - val_loss: 1.9388 - val_acc: 0.5120\n",
      "Epoch 55/2000\n",
      "140/140 [==============================] - 0s 121us/sample - loss: 0.9848 - acc: 0.8714 - val_loss: 1.9439 - val_acc: 0.5180\n",
      "Epoch 56/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 0.9517 - acc: 0.9000 - val_loss: 1.9515 - val_acc: 0.5140\n",
      "Epoch 57/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 1.0139 - acc: 0.8786 - val_loss: 1.9598 - val_acc: 0.5180\n",
      "Epoch 58/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 0.9764 - acc: 0.8929 - val_loss: 1.9758 - val_acc: 0.5080\n",
      "Epoch 59/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 0.9695 - acc: 0.8714 - val_loss: 1.9808 - val_acc: 0.5060\n",
      "Epoch 60/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 1.0882 - acc: 0.8214 - val_loss: 1.9598 - val_acc: 0.5120\n",
      "Epoch 61/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 1.0410 - acc: 0.8357 - val_loss: 1.9342 - val_acc: 0.5160\n",
      "Epoch 62/2000\n",
      "140/140 [==============================] - 0s 148us/sample - loss: 1.0683 - acc: 0.8429 - val_loss: 1.9243 - val_acc: 0.5240\n",
      "Epoch 63/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 1.0014 - acc: 0.8500 - val_loss: 1.9255 - val_acc: 0.5240\n",
      "Epoch 64/2000\n",
      "140/140 [==============================] - 0s 121us/sample - loss: 1.0179 - acc: 0.8714 - val_loss: 1.9336 - val_acc: 0.5320\n",
      "Epoch 65/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 1.0542 - acc: 0.8571 - val_loss: 1.9394 - val_acc: 0.5320\n",
      "Epoch 66/2000\n",
      "140/140 [==============================] - 0s 176us/sample - loss: 0.9669 - acc: 0.8786 - val_loss: 1.9402 - val_acc: 0.5440\n",
      "Epoch 67/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 0.9890 - acc: 0.8714 - val_loss: 1.9355 - val_acc: 0.5440\n",
      "Epoch 68/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 0.9599 - acc: 0.8857 - val_loss: 1.9301 - val_acc: 0.5400\n",
      "Epoch 69/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 1.1054 - acc: 0.8429 - val_loss: 1.9310 - val_acc: 0.5340\n",
      "Epoch 70/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 0.9602 - acc: 0.8786 - val_loss: 1.9309 - val_acc: 0.5320\n",
      "Epoch 71/2000\n",
      "140/140 [==============================] - 0s 119us/sample - loss: 0.9929 - acc: 0.8500 - val_loss: 1.9313 - val_acc: 0.5260\n",
      "Epoch 72/2000\n",
      "140/140 [==============================] - 0s 119us/sample - loss: 0.9865 - acc: 0.8500 - val_loss: 1.9171 - val_acc: 0.5300\n",
      "Epoch 73/2000\n",
      "140/140 [==============================] - 0s 118us/sample - loss: 0.9734 - acc: 0.8786 - val_loss: 1.9066 - val_acc: 0.5240\n",
      "Epoch 74/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 0.9828 - acc: 0.8571 - val_loss: 1.8998 - val_acc: 0.5220\n",
      "Epoch 75/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 0.9545 - acc: 0.8857 - val_loss: 1.9021 - val_acc: 0.5260\n",
      "Epoch 76/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 1.0607 - acc: 0.8429 - val_loss: 1.9082 - val_acc: 0.5160\n",
      "Epoch 77/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 0.9780 - acc: 0.8714 - val_loss: 1.9158 - val_acc: 0.5180\n",
      "Epoch 78/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 0.9861 - acc: 0.8643 - val_loss: 1.9192 - val_acc: 0.5240\n",
      "Epoch 79/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 1.0064 - acc: 0.8714 - val_loss: 1.9282 - val_acc: 0.5160\n",
      "Epoch 80/2000\n",
      "140/140 [==============================] - 0s 119us/sample - loss: 1.0235 - acc: 0.8857 - val_loss: 1.9342 - val_acc: 0.5140\n",
      "Epoch 81/2000\n",
      "140/140 [==============================] - 0s 116us/sample - loss: 0.9731 - acc: 0.8786 - val_loss: 1.9317 - val_acc: 0.5200\n",
      "Epoch 82/2000\n",
      "140/140 [==============================] - 0s 117us/sample - loss: 1.0083 - acc: 0.8571 - val_loss: 1.9236 - val_acc: 0.5120\n",
      "Epoch 83/2000\n",
      "140/140 [==============================] - 0s 121us/sample - loss: 0.9887 - acc: 0.8643 - val_loss: 1.9233 - val_acc: 0.5160\n",
      "Epoch 84/2000\n",
      "140/140 [==============================] - 0s 116us/sample - loss: 1.0092 - acc: 0.8714 - val_loss: 1.9237 - val_acc: 0.5220\n",
      "Epoch 85/2000\n",
      "140/140 [==============================] - 0s 117us/sample - loss: 0.9595 - acc: 0.8571 - val_loss: 1.9259 - val_acc: 0.5080\n",
      "Epoch 86/2000\n",
      "140/140 [==============================] - 0s 119us/sample - loss: 0.9904 - acc: 0.8571 - val_loss: 1.9297 - val_acc: 0.5040\n",
      "Epoch 87/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 0.8962 - acc: 0.8786 - val_loss: 1.9264 - val_acc: 0.5060\n",
      "Epoch 88/2000\n",
      "140/140 [==============================] - 0s 121us/sample - loss: 0.9975 - acc: 0.8500 - val_loss: 1.9211 - val_acc: 0.5040\n",
      "Epoch 89/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 0.9534 - acc: 0.9000 - val_loss: 1.9146 - val_acc: 0.5000\n",
      "Epoch 90/2000\n",
      "140/140 [==============================] - 0s 123us/sample - loss: 0.9848 - acc: 0.8571 - val_loss: 1.9102 - val_acc: 0.5020\n",
      "Epoch 91/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 0.9784 - acc: 0.8857 - val_loss: 1.9123 - val_acc: 0.5160\n",
      "Epoch 92/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 1.0710 - acc: 0.8429 - val_loss: 1.9169 - val_acc: 0.5160\n",
      "Epoch 93/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 1.0514 - acc: 0.8429 - val_loss: 1.9155 - val_acc: 0.5220\n",
      "Epoch 94/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 0.9535 - acc: 0.9000 - val_loss: 1.9202 - val_acc: 0.5200\n",
      "Epoch 95/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 1.0389 - acc: 0.8357 - val_loss: 1.9177 - val_acc: 0.5200\n",
      "Epoch 96/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 0.9782 - acc: 0.8500 - val_loss: 1.9161 - val_acc: 0.5040\n",
      "Epoch 97/2000\n",
      "140/140 [==============================] - 0s 129us/sample - loss: 0.9610 - acc: 0.8857 - val_loss: 1.9253 - val_acc: 0.5060\n",
      "Epoch 98/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 0.9232 - acc: 0.8929 - val_loss: 1.9348 - val_acc: 0.5140\n",
      "Epoch 99/2000\n",
      "140/140 [==============================] - 0s 124us/sample - loss: 0.9879 - acc: 0.8500 - val_loss: 1.9430 - val_acc: 0.5000\n",
      "Epoch 100/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 0.9305 - acc: 0.8643 - val_loss: 1.9518 - val_acc: 0.5020\n",
      "Epoch 101/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 1.0755 - acc: 0.8286 - val_loss: 1.9603 - val_acc: 0.5120\n",
      "Epoch 102/2000\n",
      "140/140 [==============================] - 0s 129us/sample - loss: 0.9902 - acc: 0.8571 - val_loss: 1.9742 - val_acc: 0.5140\n",
      "Epoch 103/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 0.9957 - acc: 0.8500 - val_loss: 1.9745 - val_acc: 0.5180\n",
      "Epoch 104/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 0.9435 - acc: 0.8786 - val_loss: 1.9672 - val_acc: 0.5180\n",
      "Epoch 105/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 0.9943 - acc: 0.8429 - val_loss: 1.9598 - val_acc: 0.5140\n",
      "Epoch 106/2000\n",
      "140/140 [==============================] - 0s 143us/sample - loss: 0.9587 - acc: 0.8786 - val_loss: 1.9472 - val_acc: 0.5140\n",
      "Epoch 107/2000\n",
      "140/140 [==============================] - 0s 133us/sample - loss: 1.0013 - acc: 0.8857 - val_loss: 1.9344 - val_acc: 0.5200\n",
      "Epoch 108/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 1.0256 - acc: 0.8643 - val_loss: 1.9227 - val_acc: 0.5240\n",
      "Epoch 109/2000\n",
      "140/140 [==============================] - 0s 127us/sample - loss: 0.9364 - acc: 0.8786 - val_loss: 1.9134 - val_acc: 0.5220\n",
      "Epoch 110/2000\n",
      "140/140 [==============================] - 0s 130us/sample - loss: 0.9295 - acc: 0.8929 - val_loss: 1.9093 - val_acc: 0.5300\n",
      "Epoch 111/2000\n",
      "140/140 [==============================] - 0s 120us/sample - loss: 0.9431 - acc: 0.8786 - val_loss: 1.9076 - val_acc: 0.5260\n",
      "Epoch 112/2000\n",
      "140/140 [==============================] - 0s 121us/sample - loss: 0.9432 - acc: 0.8929 - val_loss: 1.9113 - val_acc: 0.5300\n",
      "Epoch 113/2000\n",
      "140/140 [==============================] - 0s 122us/sample - loss: 0.8972 - acc: 0.9286 - val_loss: 1.9182 - val_acc: 0.5320\n",
      "Epoch 114/2000\n",
      "140/140 [==============================] - 0s 125us/sample - loss: 0.9595 - acc: 0.8929 - val_loss: 1.9327 - val_acc: 0.5340\n",
      "Epoch 115/2000\n",
      "140/140 [==============================] - 0s 126us/sample - loss: 0.9772 - acc: 0.8857 - val_loss: 1.9440 - val_acc: 0.5300\n",
      "Epoch 116/2000\n",
      "140/140 [==============================] - 0s 128us/sample - loss: 0.9201 - acc: 0.8929 - val_loss: 1.9498 - val_acc: 0.5360\n"
     ]
    }
   ],
   "source": [
    "es_callback = EarlyStopping(\n",
    "    monitor=\"val_acc\", patience=50\n",
    ")  # patience is the number of epochs to wait before early stopping in case of no further improvement\n",
    "\n",
    "mc_callback = ModelCheckpoint(\n",
    "    \"logs/best_fc_model.h5\",\n",
    "    monitor=\"val_acc\",\n",
    "    save_best_only=True,\n",
    "    save_weights_only=True,\n",
    ")\n",
    "\n",
    "history = fully_connected_model.fit(\n",
    "    X_train,\n",
    "    train_targets,\n",
    "    validation_data=(X_val, val_targets),\n",
    "    epochs=2000,\n",
    "    batch_size=200,\n",
    "    shuffle=True,  # we can shuffle the data here as\n",
    "    callbacks=[es_callback, mc_callback],\n",
    ")  # we're only working with node features"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By itself the fully connected model only gets ~60% accuracy on the test set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2068/1 - 0s - loss: 1.9270 - acc: 0.5348\n",
      "\n",
      "Test Set Metrics:\n",
      "\tloss: 1.9185\n",
      "\tacc: 0.5348\n"
     ]
    }
   ],
   "source": [
    "X_test = test_data[feature_names].values.astype(np.float32)\n",
    "\n",
    "fully_connected_model.load_weights(\"logs/best_fc_model.h5\")\n",
    "test_metrics = fully_connected_model.evaluate(X_test, test_targets, verbose=2)\n",
    "print(\"\\nTest Set Metrics:\")\n",
    "for name, val in zip(fully_connected_model.metrics_names, test_metrics):\n",
    "    print(\"\\t{}: {:0.4f}\".format(name, val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we propogate the fully connected network - no extra training required and we can re-use the APPNP object we've already created. First we create an intermediate fully connected model without the softmax layer, this is to avoid propagating the softmax layer which may cause issues with further training. We then propagate this intermediate network."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "intermediate_model = Model(\n",
    "    inputs=fully_connected_model.inputs, outputs=fully_connected_model.layers[-2].output\n",
    ")\n",
    "\n",
    "x_inp, x_out = appnp.propagate_model(intermediate_model)\n",
    "predictions = keras.layers.Softmax()(x_out)\n",
    "\n",
    "propagated_model = keras.models.Model(inputs=x_inp, outputs=predictions)\n",
    "propagated_model.compile(\n",
    "    loss=\"categorical_crossentropy\",\n",
    "    metrics=[\"acc\"],\n",
    "    optimizer=keras.optimizers.Adam(lr=0.01),\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our accuracy is better than the fully connected network by itself but less than end-to-end trained PPNP and APPNP. \n",
    "\n",
    "Note that this is partially because 140 data points isn't sufficient for the fully connected model to achieve optimal performance. As the number of training nodes increases the perfomance gap shrinks. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Test Set Metrics:\n",
      "\tloss: 1.7607\n",
      "\tacc: 0.7205\n"
     ]
    }
   ],
   "source": [
    "test_metrics = propagated_model.evaluate_generator(test_gen)\n",
    "print(\"\\nTest Set Metrics:\")\n",
    "for name, val in zip(propagated_model.metrics_names, test_metrics):\n",
    "    print(\"\\t{}: {:0.4f}\".format(name, val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Making predictions with the model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's get the predictions for all nodes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "all_nodes = node_data.index\n",
    "all_gen = generator.flow(all_nodes)\n",
    "all_predictions = propagated_model.predict_generator(all_gen)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These predictions will be the output of the softmax layer, so to get final categories we'll use the `inverse_transform` method of our target attribute specifcation to turn these values back to the original categories."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that for full-batch methods the batch size is 1 and the predictions have shape $(1, N_{nodes}, N_{classes})$ so we remove the batch dimension to obtain predictions of shape $(N_{nodes}, N_{classes})$ using the NumPy `squeeze` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "node_predictions = target_encoding.inverse_transform(all_predictions.squeeze())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's have a look at a few predictions after training the model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Predicted</th>\n",
       "      <th>True</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>31336</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1061127</th>\n",
       "      <td>subject=Theory</td>\n",
       "      <td>Rule_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1106406</th>\n",
       "      <td>subject=Reinforcement_Learning</td>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13195</th>\n",
       "      <td>subject=Reinforcement_Learning</td>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37879</th>\n",
       "      <td>subject=Probabilistic_Methods</td>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1126012</th>\n",
       "      <td>subject=Probabilistic_Methods</td>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1107140</th>\n",
       "      <td>subject=Reinforcement_Learning</td>\n",
       "      <td>Theory</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1102850</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31349</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1106418</th>\n",
       "      <td>subject=Theory</td>\n",
       "      <td>Theory</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1123188</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1128990</th>\n",
       "      <td>subject=Genetic_Algorithms</td>\n",
       "      <td>Genetic_Algorithms</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>109323</th>\n",
       "      <td>subject=Probabilistic_Methods</td>\n",
       "      <td>Probabilistic_Methods</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>217139</th>\n",
       "      <td>subject=Case_Based</td>\n",
       "      <td>Case_Based</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>31353</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>32083</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1126029</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Reinforcement_Learning</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1118017</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>49482</th>\n",
       "      <td>subject=Neural_Networks</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>753265</th>\n",
       "      <td>subject=Theory</td>\n",
       "      <td>Neural_Networks</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                              Predicted                    True\n",
       "31336           subject=Neural_Networks         Neural_Networks\n",
       "1061127                  subject=Theory           Rule_Learning\n",
       "1106406  subject=Reinforcement_Learning  Reinforcement_Learning\n",
       "13195    subject=Reinforcement_Learning  Reinforcement_Learning\n",
       "37879     subject=Probabilistic_Methods   Probabilistic_Methods\n",
       "1126012   subject=Probabilistic_Methods   Probabilistic_Methods\n",
       "1107140  subject=Reinforcement_Learning                  Theory\n",
       "1102850         subject=Neural_Networks         Neural_Networks\n",
       "31349           subject=Neural_Networks         Neural_Networks\n",
       "1106418                  subject=Theory                  Theory\n",
       "1123188         subject=Neural_Networks         Neural_Networks\n",
       "1128990      subject=Genetic_Algorithms      Genetic_Algorithms\n",
       "109323    subject=Probabilistic_Methods   Probabilistic_Methods\n",
       "217139               subject=Case_Based              Case_Based\n",
       "31353           subject=Neural_Networks         Neural_Networks\n",
       "32083           subject=Neural_Networks         Neural_Networks\n",
       "1126029         subject=Neural_Networks  Reinforcement_Learning\n",
       "1118017         subject=Neural_Networks         Neural_Networks\n",
       "49482           subject=Neural_Networks         Neural_Networks\n",
       "753265                   subject=Theory         Neural_Networks"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "results = pd.DataFrame(node_predictions, index=all_nodes).idxmax(axis=1)\n",
    "df = pd.DataFrame({\"Predicted\": results, \"True\": node_data[\"subject\"]})\n",
    "df.head(20)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we have an accurate model that can handle large graphs."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
